Skip to content
On this page

跨域

同源策略

我们把协议、域名、端口号都相同的两个 URL 称为同源,在网页中不同源的交互通常可以分为以下三类:

  • 跨域写操作(Cross-origin writes)一般是被允许的。例如链接(links),重定向以及表单提交。
  • 跨域源嵌入(Cross-origin embedding)一般是被允许,比如 script、img 等
  • 跨域读操作(Cross-origin reads)一般是不被允许的

当受到同源策略限制时,浏览器会提示资源被限制访问 blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource,并提示需要在响应头提供 Access-Control-Allow-Origin 字段,可以用以下的解决方案来解决跨域问题

CORS

跨域资源共享(CORS)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他 origin,从而使浏览器可以访问加载这些资源。

cors 需要浏览器浏览器和服务器同时支持,IE 浏览器不能低于 IE 10。

浏览器将 CORS 分为了简单请求和非简单请求

简单请求

对于简单请求,浏览器直接发出 CORS 请求。会在请求头上,增加 Origin 字段,用来标示请求源(协议+域名+端口)。

如果 Origin 指定的源,不在许可范围内的源,会返回一个正常的 HTTP 回应。浏览器发现响应头没有包含Access-Control-Allow-Origin 字段,就会被同源策略拦截

所以要想不被同源策略拦截,需要在响应头上加上 Access-Control-Allow-Origin 字段,可以是 *,表示接受任意域名的请求,也可以是指定的可访问域名,以 koa 为例

js
ctx.set("Access-Control-Allow-Origin", "*")
ctx.set("Access-Control-Allow-Origin", "http://localhost:8080")

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE

非简单请求的 CORS 之前,会增加一个“预检”请求(preflight),这是浏览器自动发起的 options 请求,无需开发者手动操作。

所以需要服务器额外对OPTIONS方法进行额外的处理,以 koa 为例

js
ctx.set("Access-Control-Allow-Origin", "http://192.168.31.168:8080")
ctx.set("Access-Control-Allow-Methods", "GET,POST,PUT")

需要在响应头设置Access-Control-Allow-Origin指定允许跨域的源,接着设置Access-Control-Allow-Methods字段,即允许这个方法跨域

在这个 options 方法做出了响应之后,浏览器就会发出实际的请求出来了,服务器做出相应的处理即可

JSONP

script 脚本是不会受到同源策略影响的,所以我们也可以使用 script 脚本来实现跨域,这就叫做 JSONP,例如

html
<script src="http://localhost:3000/?callback=back"></script>

我们封装一个更通用的函数来实现 JSONP

js
jsonp(url, callback, fn) {
  let script = document.createElement("script")
  script.src = `${url}/?${callback}=back`
  window.back = function(data) {
    fn(data)
  }
  document.body.appendChild(script)
},


function fn(res) {
    console.log(res)
}

jsonp("http://localhost:3000/", "callback", fn)

然后在服务端做相应的处理,以 koa 为例,在 get 的处理中

js
let { query } = ctx.request
let { callback } = query

ctx.body = `${callback}(124)`