前端-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) {
w.Header().Add("Access-Control-Allow-Origin", "*")
return
}

Access-Control-Allow-Origin 是指可以跨域访问本地资源的源域

非简单请求

处理POST、PUT、GET这些复杂请求,或者更精确的控制CORS,比如允许的源范围,是否允许Cookie

对于任何非简单请求,浏览器会先与服务器进行沟通,达成一致后,再发出实际请求。
Preflight请求
在发起实际请求前,浏览器首先通过OPTIONS方式(这样才能从任何服务器收到响应):

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

Access-Control-Request-Method是浏览器想要发出的请求类型,
Access-Control-Request-Headers是实际请求发送过来时的额外的Header类型,这些参数都是用逗号分割的多值字符串。

服务器端响应Preflight Request如下:

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8

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();
xhr.withCredentials = true;

WebSocket

缺点:1. 不是所有的服务器都支持 2. 必须有相应的服务器支持。
优点:1. 支持实时通信,可以避免浏览器的短轮询及服务器的长轮询。 2. 长连接会带来一定的服务器内存开销

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。