其他跨域方案请看:
1、JSONP跨域方案
以下介绍CORS跨域解决方案
一、什么是CORS?CORS (Corss-Orign Resource Sharing) 是W3C工作草案,是一份浏览器技术的规范。定义了跨域资源访问时,浏览器和服务器之间如何通信,使用自定义的http头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。CORS在现代浏览器都支持,使用和普通的ajax没有任何区别,关键是只要服务器实现CORS接口。
二、如何使用
现代浏览器都支持CORS,所以前端不需要做任何改变,即使普通的ajax,只需要服务器实现CORS接口;http如何请求服务器,我们不会有如何感觉。
三、服务端处理流程
HTTP请求
1、查看http头部是否有Origin,没有直接结束,有到第2步。
2、查看Origin是否有效,无效则返回403,有效则第3步。
3、查看method是否有效,无效则返回403,是有效则第4步。
4、查看是否是OPTION请求,不是则简单请求处理,是则预检处理。
简单请求处理:
返回Allow-Origin, Allow-Credentials等,并返回正常内容
预检处理:
返回Allow-Origin, Allow-Credentials等,内容为空,只有当浏览器下一次发出实际http请求才返回内容
四、客户端处理机制
浏览器将CORS请求分成两类:简单请求和预检请求(非简单请求),不需要做其他设置
划分的依据为:
(1) 简单请求(需要同时满足下面两个条件)
请求方法是:HEAD ,GET,POST 三者之一
HTTP头信息不超过以下字段:Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
简单请求时,浏览器会直接发起一个跨域请求,并在请求头中携带上Origin,用来说明本次请求来自哪个源。服务器端接受到请求后,根据头信息来判断是否允许跨域,返回一个正常的HTTP响应(如果允许,则响应头携带Access-Control-Allow-Origin等字段,并返回正常内容)。浏览器根据返回的响应头是否携带Access-Control-Allow-Origin等字段判断请求是否请求成功,没有则抛出异常。注意:请求是否成功不能通过状态码来确定,因为有可能也是200,但是请求拒绝了。
异常:
正确:
(2) 非简单请求
只要不能同时满足简单请求中任意一个条件的就是非简单请求,如果预检成功,浏览器实际一共会发送两次请求。
分别:
option请求
预检成功则发送正常的post请求
五、服务器端配置
服务器端可以在多个地方设置,比如ngnix、oss、cdn、web服务器等
主要涉及到的是:
NameRequiredCommentsAccess-Control-Allow-Origin必填允许请求的域,比如:http://www.baidu.com或者所有都允许*Access-Control-Allow-Methods必填允许请求的方法,比如:get、post、put、delete,多个用逗号分割,或者允许所有*Access-Control-Allow-Headers可选预检请求后,告知发送请求需要有的头部Access-Control-Expose-Headers可选CORS请求时,xmlhttprequest默认只能拿到6个基本字段:Cache-Control、
Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿
到其他字段,就必须在Access-Control-Expose-Headers里面指定。
Access-Control-Max-Age可选本次预检的有效期,单位:秒;在有效期内不需要发出另一条预检Access-Control-Allow-Credentials可选表示是否允许发送cookie,默认false;比如put或delete,浊者content-type为
application/json等的有特殊要求,需要设置为true
1、web服务器
可以通过添加过滤器,或拦截器等处理
<filter><display-name>CORSFilter</display-name><filter-name>CORSFilter</filter-name><filter-class>com.learn.mybatis.controller.filter.CORSFilter</filter-class></filter><filter-mapping><filter-name>CORSFilter</filter-name><url-pattern>/home</url-pattern></filter-mapping> public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse response2 = (HttpServletResponse) response; response2.setHeader("Access-Control-Allow-Origin", "*"); response2.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE"); response2.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization"); response2.setHeader("Access-Control-Max-Age", "10"); chain.doFilter(request, response2);}
2、ngnix
来源:https://michielkalkman.com/snippets/nginx-cors-open-configuration/
location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; # # Om nom nom cookies # add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # Custom headers and headers various browsers **should** be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Credentials' 'true'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; }}
3、oss
比如阿里云中,
进入OSS管理控制台界面。在左侧存储空间列表中,单击目标存储空间名称,打开该存储空间概览页面。单击基础设置页签,找到跨域设置区域,然后单击设置。
4、cdn
六、带认证的请求
CORS默认情况下是不需要提供cookie,http认证,ssl等的,如果需要携带认证,则需要设置
xmlhttprequest.withCredentials = true;服务器端需要设置:
Access-Control-Allow-Credentials为true。
不然会报错:
当服务器设置带认证,则Access-Control-Allow-Origin不能设置为*,必须为一个具体的域名。
不然也会报错:
设置正确后,将携带上cookie:
七、错误处理
因为CORS错误,浏览器有可能返回的也是200,所以通过状态码无法判定是否出错。
可以使用onerror监听错误,使用onload检测成功
xhr.onerror = function(){ conlose.log("cors error");}八、弊端、缺陷
1、只要服务器Access-Control-Allow-Origin不要设置成*,同时做好认证,在安全性上是比较可靠的,但是在低版本浏览器上并不支持,只能使用jsonp。
2、这点比较重要,CORS的两种请求方式:简单请求和非简单请求;即第一种是先发起请求,然后拦截返回数据;第二种是先请求验证进行拦截,再发起请求。
所以对于简单请求来讲,即使返回数据被拦截,但是实际走过了后台的整个逻辑,即更新数据库的更新数据库等,但是到浏览器端却通过onerror报请求失败。
九、JSONP和CORS比较 NameCompareUsage安全性
因为JSONP不是规范,所以存在很明显的安全漏洞,比如callback注入等。
但是安全没有绝对性,CORS也同样存在漏洞。CORS简单请求失败也会更新数据,这个漏洞在简单请求中存在。
兼容性JSONP兼容型很强,CORS只支持现在浏览器,低版本ie等不支持低版本使用JSONP,现在浏览器推荐CORS请求方式JSONP只能使用GET,CORS支持所有的http请求有增删改查,推荐使用CORS错误处理JSONP错误处理不完善,CORS可以监听onerror,并通过浏览器控制台查看 复杂度JSONP发送一次get请求,CORS非简单请求会发送两次,第一次预检参考:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS