前端-CORS问题
总结一下,跨域访问的问题。
出现请求跨域错误主要原因
是因为浏览器的“同源策略”。
浏览器安全的基石是”同源政策”(same-origin policy)
最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页”同源”。所谓”同源”指的是”三个相同”。
- 协议相同
- 域名相同
- 端口相同
举例来说,http://www.example.com/dir/page.html这个网址
协议是http://,域名是www.example.com,端口是80(默认端口可以省略)
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
因为浏览器同时还规定,提交表单不受同源政策的限制。
限制范围
随着互联网的发展,”同源政策”越来越严格。目前,如果非同源,共有三种行为受到限制。
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。
- AJAX 请求不能发送。
解决方法
这里只关心用到的ajax调用
AJAX
主要有三种方法,规避:JSONP,WebSocket,CORS
目前看 WebSocket,CORS 用的比较多。JSONP局限性比较大
JSONP
这个不是最好的选择。只支持 get 请求,还有其他缺点,不需要写了。
CORS
优点:1. 相比于JSONP,不仅支持get请求,也支持post、put等请求。
缺点:1. 不是所有的浏览器都支持 2. 需要服务器支持
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
浏览器将CORS分为了两类:简单请求和非简单请求
简单请求
任何简单请求必须满足一系列限制
对于简单的CORS请求,最简单的处理方法是,增加以下一行到你的Response Header里
func setAllowOrigin(w http.ResponseWriter, r *http.Request) { |
Access-Control-Allow-Origin 是指可以跨域访问本地资源的源域
非简单请求
处理POST、PUT、GET这些复杂请求,或者更精确的控制CORS,比如允许的源范围,是否允许Cookie
对于任何非简单请求,浏览器会先与服务器进行沟通,达成一致后,再发出实际请求。
Preflight请求
在发起实际请求前,浏览器首先通过OPTIONS方式(这样才能从任何服务器收到响应):
OPTIONS /cors HTTP/1.1 |
Access-Control-Request-Method是浏览器想要发出的请求类型,
Access-Control-Request-Headers是实际请求发送过来时的额外的Header类型,这些参数都是用逗号分割的多值字符串。
服务器端响应Preflight Request如下:
Access-Control-Allow-Origin: http://api.bob.com |
Access-Control-Allow-Origin为CORS响应标配。
Access-Control-Allow-Methods 和 Access-Control-Allow-Headers是服务器端支持的方法和头信息。值得注意的是,这里应该填写全集,而非对应Preflight请求里的项目。
Access-Control-Max-Age是告诉浏览器多少秒以内,不需要再请求Preflight.
Access-Control-Allow-Credentials是告诉浏览器是否支持Cookie
withCredentials 属性
CORS请求默认不包含Cookie信息(以及HTTP认证信息等)。如果需要包含Cookie信息,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest(); |
WebSocket
缺点:1. 不是所有的服务器都支持 2. 必须有相应的服务器支持。
优点:1. 支持实时通信,可以避免浏览器的短轮询及服务器的长轮询。 2. 长连接会带来一定的服务器内存开销
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。