为什么会这样

同源策略

先说一下这个同源策略。
他为什么出现,为了安全。
通过限制不同源之间的交互,避免一些浏览器网络层面的攻击:

  • XSS
  • CSFR

    什么叫不同源

    知道什么叫同源就知道什么是不同源了。
    协议、域名、端口一样就是同源。后面的请求路径、请求参数、锚点什么的不重要。

    讲一下怎么防住这些攻击的

    XSS就是往页面中插入恶意的 html 代码 —— 利用用户对网站的信用,用户以为自己做的是自己想做的
    CSFR 就是跨站请求伪造,骗有权限的浏览器去做操作,因为用户给过他权限,浏览器就以为是用户自己想做的

不设置同源策略,就会导致只能保证请求来自用户的浏览器,但是不能保证这是用户自己真正想做的
而非同源的可以限制网站行为,不给你看 cookie、localStorage、indexDB、请求等,就不能通过用户历史访问留下的权限进行恶意操作


为什么要跨域

现在项目基本前后端分离,就会处在不同的域名上。当前端直接请求后端的接口,就会报错。很安全,但是很不方便 ==

就自己本地启两服务器端口号都会不一样好吧

那要怎么跨过去

JSONP

AJAX/XMLHttpRequest/FetchAPI的方式来发起请求是会收到跨域拦截的,但是 html 中调用 JS 是没事的—— 也就是说,拥有 src 属性的 标签就能跨域。
JSONP 就是这样,通过发送带有会回调函数 的 GET 请求,让服务器端将接口返回数据作为参数放到回调函数里。客户端就能拿到 回调函数的数据。

有点像 react 中子组件向父组件传递信息的方式有没有

但是这个方法限制极大

  1. 只有 get 方法,因为标签请求外部资源也就只是 get 方法
  2. 把操作数据的方法放到标签里面,本来就很不方便

    代理跨域

    在前后端加一层代理,让跨域请求没“跨域”

    webpack 设置代理

    在 webpack 中可以设置 proxy 来得到接口代理的能力,代理服务器会将前端发送的请求映射为 同域请求
    1. module.exports = {
    2. //...
    3. devServer: {
    4. //...
    5. proxy: {
    6. //...
    7. }
    8. },
    9. //...
    10. };
    类似原理的还有:
  • Nginx 方向代理
  • Node 中间件代理

    CORS 跨域

    Cross-Origin Resource Sharing 跨域资源共享,这是浏览器自身提供的功能
    作用就是允许服务器规定哪些 域 是可以跨域过去的

    现代浏览器基本都支持,一般推荐用这个

虽然说这是浏览器提供的功能,但是具体实现控制和通信是在服务器端。由服务器端来控制哪些域可以跨域

简单请求

怎么算简单请求:

方法简单

比如这几种

  • get
  • post
  • head

    头部简单

    头部拥有的属性仅在这下面几个范围内

  • Accept

  • Accept-Language
  • Content-Language
  • Content-Type
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

      比如你自己自定义一个头部字段的请求就不属于简单请求的

XMLHttpRequestUpload 简单

XMLHttpRequest.upload 属性返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。这个对象是不透明的,但是作为一个XMLHttpRequestEventTarget,可以通过对其绑定事件来追踪它的进度。

  • XMLHttpRequestUpload 对象上没有注册事件监听
  • XMLHttpRequestUpload 可以用 XMLHttpRequest.upload 属性访问

ReadableStream 简单

流操作 API 中的ReadableStream 接口呈现了一个可读取的二进制流操作。Fetch API 通过 Response 的属性 body(en-US) 提供了一个具体的 ReadableStream 对象。

这个直接不能有

操作

浏览器发出 CORS 请求时,要在头部添加 Origin 字段来告诉服务端请求域
当服务端收到 Origin ,就会判断是否接受跨域请求:

  • 接受就在返回的响应中添加 CORS 相关的信息
    • Access-Control-Allow-Origin字段(必填),表示能够给接受的域名,*表示全部域名
  • 不添加相关字段的话就是不同意
    • 返回正常的 Http 响应,但是浏览器就会发现不对劲,就会抛出跨域错误

非简单请求

非简单请求,就是不是简单请求的请求
除了简不简单的区别,还有他在发送正式请求之前,会先发出一个预检请求。必须得到服务端同意请求才能发送正式请求~

预检查请求

用的请求方法是 Option ,必须标明 Origin,并且带上两个特殊字段:

  • Access-Control-Request-Method:告诉服务器端正式请求想要用到的请求方法
  • Access-Control-Request-Headers:告诉服务器端正式请求想要用到的额外头部字段

服务器端收到请求后,也会返回这两个字段来告诉他能接受的请求方法和额外头部字段。

而正式请求就和简单请求差不多了,前面两个字段的作用也就差不多是扩充简单请求的约束范围:

  • 方法简单
  • 头部简单

然后就是一样的,同意跨域就加上Access-Control-Allow-Origin…不重复赘述了

CORS 小结

CORS 跨域算是比较常用、好用、重要的方法,主要实现在于服务器端,需要在服务器端设置允许跨域的

  • 域名 Access-Control-Allow-Origin
  • 请求方法Access-Control-Allow-Methods
  • 请求头部Access-Control-Allow-Headers

    总结

    能上 CORS 就上 CORS 就好了