緣由:同源策略javascript
Ajax直接請求普通文件存在跨域無權限訪問的問題 ,數據沒法請求,可是 script 請求js確能夠正常訪問。html
jsonp就是模仿一個 script請求 來獲取數據的方式,全部基本支持的是 GET 請求前端
$.ajax({ async: false, type: 'get', jsonp: "callback",//設置這個會替換瀏覽器發送請求時地址後面自動添加的?callback=xxx中的callback這個字,通常狀況下不用傳這個參數 jsonpCallback: "callJsonP",//這個值將用來取代jQuery自動生成的隨機函數名,也就是上句話中的'xxx'。 data:自定義 url: 'http://lnn.wuage.com:8080/pc/toJson', dataType: 'jsonp', success: function (data) { alert(JSON.stringify(data)); } });
@RequestMapping("/toJson") @ResponseBody public String toJson(HttpServletRequest request,@RequestParam(value="callback")String callback) { return callback + "(" + new JSONObject() + ")"; //或者 fastJSON JSONObject obj=new JSONObject(); obj.put("data","你好呀"); JSONPObject result=new JSONPObject("callJsonP"); result.addParameter(obj); String resultStr=result.toString(); return resultStr; }
適用場景:承載的信息量大,get形式搞不定,需選用post傳輸。CORS支持全部類型的傳輸。java
兼容性:移動端全面支持(除opera mini),PC上IE8+。jquery
經常使用頭web
Access-Control-Allow-Origin: http://foo.org Access-Control-Max-Age: 3628800 Access-Control-Allow-Methods: GET,PUT, DELETE Access-Control-Allow-Headers: content-type "Access-Control-Allow-Origin"代表它容許"http://foo.org"發起跨域請求 "Access-Control-Max-Age"代表在3628800秒內,不須要再發送預檢驗請求,能夠緩存該結果 "Access-Control-Allow-Methods"代表它容許GET、PUT、DELETE的外域請求 "Access-Control-Allow-Headers"代表它容許跨域請求包含content-type頭
只使用 GET, HEAD 或者 POST 請求方法:若是使用 POST 向服務器端傳送數據,則數據類型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一種ajax
不會使用自定義請求頭(相似於 X-Modified 這種):HTTP頭部信息不超出如下{Accept,Accept-Language,Content-Language,Last-Event-ID,content-type(只限於上面提到的3種類型)}spring
失敗狀況json
若是這個源不在許可範圍內,會報錯: No 'Access-Control-Allow-Origin' header is present on the requested resource.api
對於簡單請求,瀏覽器直接發出CORS請求。瀏覽器會自動在頭信息(Request Headers)中,添加一個Origin 字段,來代表本次請求來自哪一個域。
若是Origin指定的域名在許可範圍內(必須是跨域了的),Response Headers中會多出幾個頭信息字段。
Access-Control-Allow-Credentials:true//值爲true表示容許發送cookie Access-Control-Allow-Methods:GET, POST, OPTIONS Access-Control-Allow-Origin:http://localhost:8080 Access-Control-Max-Age:1728000
例如
withCredentials屬性
由於CORS默認不發送cookie和http認證,若是要把Cookie發到服務器,就要指定Access-Control-Allow-Credentials:true;
@CrossOrigin(origins="*",allowCredentials="true") 或者 response.setHeader("Access-Control-Allow-Credentials","true");
另外AJAX中也要打開withCredentials屬性。
var xhr=new XMLHttpRequest(); xhr.withCredentials=true;
jquery ajax請求參數中加入
xhrFields: { withCredentials: true }
除了上面說的簡單請求外都是非簡單請求,好比:請求方法是PUT
或DELETE,或者Content-Type字段的類型是application/json,又或者有自定義請求頭Access-Control-Request-Headers: X-Custom-Header。
好比,我添加自定義請求頭
xhr.setRequestHeader('Some-Custom-Response-Header', 'value');
就會發現連續向同一地址請求了兩次
第一次 options 請求
第二次請求:真實請求
這是由於瀏覽器發現,這是一個非簡單請求,就自動發出一個"預檢"請求,要求服務器確承認以這樣請求。"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。"預檢"請求以後,瀏覽器球會進行正常CORS請求。
在方法體內使用 HttpServletRequest 進行跨越參數設置。若是有參數,必須參數符合要求才進行
跨越參數設置。不然報錯 400 bad requset,無返回信息
@RequestMapping("/toJson",method = RequestMethod.POST,produces="application/json; charset=utf-8") @ResponseBody public String toJson(HttpServletRequest request) { //設置哪些域名能夠訪問---若是方法有參數直接報 400 bad request 錯誤 response.setHeader("Access-Control-Allow-Origin", "*"); //解決亂碼,緣由 springmvc 設置 produces="application/json; charset=utf-8" 未生效 response.setContentType( "application/json; charset=utf-8" ); return new JSONObject(); }
使用 @CorssOrigin 在進方法體之間就對跨域參數作出設置。發生錯誤有返回信息。
Controller中的action的請求方法是實際方法就能夠,options方法默認支持
@CrossOrigin(origins="*")/**方法一:跨越參數有返回,有參時報錯參數缺失*/ @RequestMapping(value="/toJson",method = {RequestMethod.GET},produces="application/json;charset=utf-8") @ResponseBody public String toJson(HttpServletRequest request,HttpServletResponse response){ return new JSONObject("ni你好點的"); }
<mvc:cors> <mvc:mapping path="/api/**" allowed-origins="*" allowed-methods="GET,POST,PUT,OPTIONS" allow-credentials="false" max-age="3600" /> </mvc:cors>
支持SpringMvc 4以上 ,測試未生效
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(false).maxAge(3600); } }
注入:
<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>
<mvc:interceptors> <mvc:interceptor> <!--過濾的路徑--> <mvc:mapping path="/h5/*" /> <bean class="com.wuage.ossserver.web.Interceptor.CorsInterceptor"> <!--過濾路徑中的不須要過濾的路徑--> <property name="excludedUrls"> <list> <value>/h5/testOrigin</value> </list> </property> </bean> </mvc:interceptor> <mvc:interceptors>
package com.wuage.ossserver.web.Interceptor; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; /** * 請求攔截器,處理跨域問題 * @author 李寧寧 * */ public class CorsInterceptor implements HandlerInterceptor { private List<String> excludedUrls; public List<String> getExcludedUrls() { return excludedUrls; } public void setExcludedUrls(List<String> excludedUrls) { this.excludedUrls = excludedUrls; } /** * * 在業務處理器處理請求以前被調用 若是返回false * 從當前的攔截器往回執行全部攔截器的afterCompletion(), * 再退出攔截器鏈, 若是返回true 執行下一個攔截器, * 直到全部的攔截器都執行完畢 再執行被攔截的Controller * 而後進入攔截器鏈, * 從最後一個攔截器往回執行全部的postHandle() * 接着再從最後一個攔截器往回執行全部的afterCompletion() * * @param request * * @param response */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //* 能夠替換成 特定的 網址(協議 域名 端口) response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); response.setHeader("Access-Control-Allow-Credentials", "true"); return true; } // 在業務處理器處理請求執行完成後,生成視圖以前執行的動做 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } /** * * 該方法也是須要當前對應的Interceptor的preHandle方法的返回值爲true時纔會執行。 * 該方法將在整個請求完成以後,也就是DispatcherServlet渲染了視圖執行, 這個方法的主要做用是用於清理資源的, * * @param request * * @param response * * @param handler * */ public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
<filter> <filter-name>cros</filter-name> <filter-class>com.wuage.ossserver.web.Interceptor.CORSFilter</filter-class> </filter> <filter-mapping> <filter-name>cros</filter-name> <url-pattern>/h5/*</url-pattern> </filter-mapping>
public class CORSFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException { HttpServletResponse localHttpServletResponse = (HttpServletResponse)response; localHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*"); localHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE,OPTIONS"); localHttpServletResponse.addHeader("Access-Control-Allow-Headers", "Content-Type"); localHttpServletResponse.addHeader("Access-Control-Max-Age", "1800"); filterChain.doFilter(request, response); } @Override public void destroy() {} @Override public void init(FilterConfig arg0) throws ServletException {} }
注意: 使用 方法 1,2 控制器中只須要進行 特定的方法設置,無需就添加 例如 options類型的設計
options 非簡單CORS請求中 嗅探 方法類型
<input type="file" id="file_upload"/> <input type="button" value="上傳圖片" id="upload"/>
function ajaxFileUpload(){ var formData = new FormData(); formData.append('file',$("#file_upload")[0].files[0]); //將文件轉成二進制形式 $.ajax({ type:"post", url:"http://localhost:8080/nitshareserver/serve/fileupload", async:false, contentType: false, //這個必定要寫 processData: false, //這個也必定要寫,否則會報錯 data:formData, dataType:'text', //返回類型,有json,text,HTML。這裏並無jsonp格式,因此別妄想能用jsonp作跨域了。 xhrFields: {withCredentials: true}, //設置是否帶驗證 cookie success:function(data){ alert(data); }, error:function(XMLHttpRequest, textStatus, errorThrown, data){ alert(errorThrown); } }); }
Springmvc模式是掛壁OPTIONS請求的,因此須要開啓
<servlet> <servlet-name>application</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
403 forbidden 無權限訪問-有時 forbox 好使,chrom 很差使
400 bad request 請求失敗, 參數不符合要求
301 服務器錯誤 或者 重定向
405 Method Not Allowed :方法錯誤(複雜請求要求有 options 方法)
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
https://my.oschina.net/wangnian/blog/689020
http://www.tuicool.com/articles/Vf2aym
http://blog.csdn.net/u012562943/article/details/53141991