# 跨域问题
# 跨域原因
跨域的原因是由于浏览器的同源策略,同源策略是一个重要的安全策略, 是对js的一种安全限制。通过浏览器发送请求时, 如果是不同源的服务返回结果会被浏览器拦截。
解决方案
CORS、JSONP、nginx反向代理 、本地代理服务器(http-server, webpack dev server)
# CORS
CORS需要浏览器和服务器同时支持, 浏览器发起AJAX跨域请求时,会自动添加一些附加的头部信息, 比如origin, 有时候可能还会有一次OPTIONS预检请求。
当有必要的时候,浏览器会自动发出一个预检请求;所以在正常情况下,前端开发者不需要自己去发这样的请求。
它一般是用了以下几个 HTTP 请求首部的 OPTIONS
(opens new window) 请求:Access-Control-Request-Method
(opens new window) 和 Access-Control-Request-Headers
(opens new window),以及一个 Origin
(opens new window) 首部。
1、简单请求
当有必要的时候,浏览器会自动发出一个预检请求;所以在正常情况下,前端开发者不需要自己去发这样的请求。只要同时满足以下两大条件,就属于简单请求
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
当使用ajax发送一个简单请求,会在请求头中增加一个Origin头信息,指定该请求发送方的域, 用于提交给服务器判断是否接受该源跨域请求,如果服务器同意该跨域访问,正常返回数据,并在响应头信息中携带添加Access-Control-Allow-Origin
头信息,值为Origin也就是发送方的域信息,这个头信息旨在告诉浏览器服务器同意了其他域访问自己,浏览器可以将该返回值返回给请求方而不要拦截。如果服务器返回的信息中没有该字段信息,这个数据将会被拦截,无法到达请求方,并且浏览器会报错。
Access-Control-Allow-Origin
头的值一般为发送方的Origin,表示同意该域,或者指定为"*",表示任意域都同意。还有2个可选择的字段
**Access-Control-Allow-Credentials:**它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可
**Access-Control-Expose-Headers:**CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
2、非简单请求
一般请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json基本都是非简单请求
当浏览器检测到需要发送一个非简单的跨域请求时,浏览器会拦截该请求,发送一个预检请求到该请求的接受方,旨在询问接受方是否同意这个非简单的跨域请求,接收方通过返回指定内容表示是否同意。
一个 CORS 预检请求是用于检查服务器是否支持 CORS (opens new window) 即跨域资源共享。它一般是用了以下几个 HTTP 请求首部的 OPTIONS
(opens new window) 请求:Access-Control-Request-Method
(opens new window) 和 Access-Control-Request-Headers
(opens new window),以及一个 Origin
(opens new window) 首部。
预检请求的的响应
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000 // 用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
# JSONP
利用src和href属性可以直接通过GET请求跨域访问其他站点的特点,而诞生了jsonp的使用方法。
直接访问服务器得到数据并直接调用,因为src不能返回后调用,只能GET数据,这个数据为一个函数调用的字符串,数据返回后在本页面找到指定函数直接调用,避开了预检请求实现跨域问题。
同一个网页的<script>
等标签中可以使用从不同域GET回来的文件,这些文件中的全局变量在该HTML文件中均可以被使用。由此,我们可以跨域获取一个函数定义,在本域中调用该函数。这将会在这个页面内直接执行这个函数获得结果。
利用该请求的特点,开始使用这样方式去解决跨域的问题,逐渐形成了一种非正式传输协议,人们把它称作」SONP,该协议的一个要点就是允许用户传递一个callback参数(参数值及为回调函数名)给服务端,然后服务端返回数据时会将这个 callback参数作为函数名来包裹住服务端的数据,产生一个类似于callback(data)
的函数调用字符串返回,这样客户端的到数据后就直接执行该字符串。而字符串中的函数客户端已定义,可以成功的被调用。
← HTTP Cookie http常用请求头 →