CORS 跨域解决方案
跨源资源共享
跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它源(域、协议和端口),使得浏览器允许这些 origin 访问加载自己的资源
跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
如下图所示:
跨域
测试
前端 地址:http://127.0.0.1:8081/hello, 后端接口地址:http://localhost:8080/test/testCors
前端 js ajax 请求代码
function detail() {$.ajax({url: "http://localhost:8080/test/testCors",data: JSON.stringify({"data":"chen"}),dataType: "json",contentType: "application/json",type: "post",/**xhrFields: {withCredentials: true //前端设置是否带cookie},crossDomain: true // 会让请求头中包含跨域的额外信息,但不会含cookie*/success: function (data) {console.log(data);}});}
前端一些特殊要求设置:
xhrFields: {
withCredentials: true //前端设置是否带cookie
},
crossDomain: true 会让请求头中包含跨域的额外信息,但不会含cookie
后端接口代码:
//@CrossOrigin(allowCredentials = "true")@RequestMapping(value = "/testCors", method = RequestMethod.POST)public String testCors(@RequestBody TestCorsDto dto) {return dto.toString();}
增加@CrossOrigin(allowCredentials = "true")
注解解决跨域问题
注解@CrossOrigin
简述
@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface CrossOrigin {@DeprecatedString[] DEFAULT_ORIGINS = {"*"};@DeprecatedString[] DEFAULT_ALLOWED_HEADERS = {"*"};@Deprecatedboolean DEFAULT_ALLOW_CREDENTIALS = false;@Deprecatedlong DEFAULT_MAX_AGE = 1800;//同origins@AliasFor("origins")String[] value() default {};/*** 支持哪些请求跨域,"*" 或 默认是支持所有地址* 同配置"Access-Control-Allow-Origin"* 如 @CrossOrigin(origins = {"http://127.0.0.1:8081","http://localhost:8081"}) 支持这两个地址跨域 * 请求*/@AliasFor("value")String[] origins() default {};/*** 支持的请求标头,"*" 或 默认是支持所有* 同配置“Access-Control-Allow-Headers”* 如:Accept-Encoding 等*/String[] allowedHeaders() default {};/*** 跨域请求暴露的响应标头* 同配置“Access-Control-Expose-Headers”* */String[] exposedHeaders() default {};/*** 支持哪些方法跨域* 同配置 “Access-Control-Allow-Methods”*/RequestMethod[] methods() default {};/*** 跨域请求默认不包含Cookie, true 表示可以设置Cookie* 同配置"Access-Control-Allow-Credentials"*/String allowCredentials() default "";/*** 表明响应的时间为多少秒,在有效时间内,浏览器无需为同一请求再次发起预检请求* 默认 -1 长久有效* 配置同 "Access-Control-Max-Age"*/long maxAge() default -1;}
两种跨域请求
简单跨域请求只需要请求一次,复杂跨域请求需要请求2次,第一次是预检请求(options请求),第二次是真是的跨域请求。
简单请求
请求方式为GET、HEAD、POST时的请求;认为设置规范集合之内的首部字段,如Accept/Accept-Language/Content-Language/Content-Type/DPR/Downlink/Save-Data/Viewport-Width/Width;Content-Type 的值仅限于下列三者之一,即application/x-www-form-urlencoded、multipart/form-data、text/plain;请求中的任意 XMLHttpRequestUpload对象均没有注册任何事件监听器;请求中没有使用 ReadableStream对象。
复杂请求(非简单请求)
PUT/DELETE/CONNECT/OPTIONS/TRACE/PATCH;人为设置了以下集合之外首部字段,即简单请求外的字段;Content-Type 的值不属于下列之一,即application/x-www-form-urlencoded、multipart/form-data、text/plain。application/json 即为复杂请求
预检请求
要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
POST 请求,格式如果为application/json
,会增加一个 预检请求(option请求)如下:
预检请求优化
当发起跨域请求时,简单请求只发起一次请求;复杂请求则需要2次,先发起options请求,确认目标资源是否支持跨域,浏览器会根据服务端响应的header自动处理剩余的请求,如果响应支持跨域,则继续发出正常请求;不支持的话,会在控制台显示错误。
所以,当触发预检时,跨域请求便会发送2次请求,增加请求次数,同时,也延迟了请求真正发起的时间,会严重地影响性能。
优化options请求的两种方法:
方法一: 用其它的跨域方式做跨域请求,将复杂请求转为简单请求,比如JSONP等;方法二: 对 options 请求进行缓存。服务器端设置 Access-Control-Max-Age 字段,那么当第一次请求该 URL 时会发出 OPTIONS 请求,浏览器会根据返回的 Access-Control-Max-Age 字段缓存该请求的 OPTIONS 预检请求的响应结果(具体缓存时间还取决于浏览器的支持的默认最大值,取两者最小值,一般为 10 分钟)。在缓存有效期内,该资源的请求(URL 和 header 字段都相同的情况下)不会再触发预检。(chrome 打开控制台可以看到,当服务器响应 Access-Control-Max-Age 时只有第一次请求会有预检,后面不会了。注意要开启缓存,去掉 disable cache 勾选。)
问题二
原因:待定……
杂项
安装 Nginx
/detail/win10_ShangAnZhu_e60a878d.html
Nginx 操作
start nginx //启动 nginxnginx.exe -s stop //停止nginxnginx.exe -s reload //重新加载nginxnginx.exe -s quit //退出nginx
Jsonp原理
利用的就是script的src标签没有跨域限制来实现的
参考:/hfdx/p/16188904.html
参考:
跨域CORS详解
常见的跨域解决方案
跨源资源共享(CORS)