浏览器跨域的认识

参考了文章 你真的了解跨域吗 - 掘金 ,做了简单的笔记和思考。

什么是跨域?

同源策略

协议、域名、端口相同 url,叫做同源。当不同源时:

  • Cookie、LocalStorage、IndexedDB 等存储性内容无法读取。
  • DOM 节点和 Js对象无法获得
  • AJAX 请求发送后,结果被浏览器拦截(注意是 请求发送出去了,也拿到结果了,只是被浏览器截胡了

跨域

跨域:一个域下的文档或脚本想要去去请求另一个域下的资源。

狭义的跨域:Ajax 发出非同源的请求,触发浏览器的同源策略限制。

跨域的处理方式

这里只讨论狭义的跨域的处理方式,也就是 Ajax 请求导致跨域拿不到数据的问题。这在前端开发中非常常见。

一、使用 JSONP

JSONP(JSON with Padding),是 JSON 的一种使用方法。虽然它的实现原理比较特殊,其实也算不上用到 JSON,但确实能做到拿到数据的效果。举例:

1
2
3
4
5
6
7
8
<script>
  let myData
	function getData(data) {
    myData = data
  }
</script>
<!-- 跨域请求 -->
<script src="http://othersite.com/api/get?callback=getData"></script>

然后跨域请求的脚本就可以根据请求字符串 callback,拼凑出 getData({ name: 'Bolt' }) 这样的字符串作为请求脚本的内容。这样,我们就实现了跨域请求。但这种方法已经过时了。

缺陷是只能发出 get 请求。

二、CORS(跨域资源共享)

简单请求 和 非简单请求

  • 简单请求:跨域请求时,直接带上 origin 头。(HTML Form 在不依赖脚本的情况下可以发出的请求)

  • 非简单请求:跨域请求时,先额外发送 OPTIONS 请求来确定服务器是否允许跨域请求,再发送真正的请求。这个额外的请求成为称为 preflight 预检请求。

image-20210810200816771

preflight 请求的内容:

image-20210810202625605

  • access-control-request-headers:真正请求中使用的请求方法
  • access-control-request-headers:超出简单请求允许范围的头字段。

服务器的 CORS 头字段

比如 github 的公共接口,请求回来的响应头中,就有 access-control-allow-origin: *,意思是任何请求源都可以请求,浏览器不必阻拦返回的数据。

https://api.github.com/search/users?q=fstar

image-20210810182143116

  • Access-Control-Allow-Origin:允许资源访问的 origin
  • Access-Control-Allow-Methods:运行资源访问可以使用的请求方法(preflight 请求可能会返回)。
  • Access-Control-Allow-Credentials:值为 true 表示可以发送 cookies。(xhr 请求要设置 xhr.withCredentials = true )此时 Cookies 依旧遵循同源策略,只有用服务器域名设置的 Cookie 才会上传。只能设置为 ture,或去掉这个头字段。
  • Access-Control-Allow-Headers:允许使用的不在简单请求内的请求头字段。
  • Access-Control-Max-Age:预检请求的缓存时间长度,如 1800 表示 1800 秒,过期发送同样的请求,就不需要再发预检请求了。

三、使用代理

同源策略只对浏览器生效,使用代理可以解决跨域问问题。

在进行开发中,我们通常会使用脚手架的代理功能,比如 webpack-dev-server、Vue 和 React 脚手架集成的代理功能。

Ajax 发起的是同源的请求,但在符合配置规则(比如 /api 开头)的情况下,会转发给真正的服务器拿到数据再转发回来。这样浏览器的请求就是同源的,不会出现跨域问题。

至于部署,常常会使用 Web 服务器进行方向代理,和开发的请求转发效果差不多。