缘由:同源策略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