前言
之前没有自己部署过前端项目, (单页面不算) (ノへ ̄、), 然后今天突然需要部署一个项目上线, 之前常用的 express 静态资源管理不管用了, 因为后端的 CORS(跨源资源共享), 然后我就傻了, 但是之前还是了解到可以使用 nginx 去配置反向代理实现跨域的。所以, 就开搞了,但是也踩了很多坑,写一下记录记录 可以到我的博客进行观看特效:gaoxiaoxin.github.io/2022/03/10/…
跨域??
首先,我们要明白我们要解决的问题的本质是什么, 也就是我们遇到的 跨域是指的是什么???
基本定义
我为了这个问题, 问了我一个很安全的搞安全的朋友, 他说跨域就要怪搞安全的,弄了一个浏览器的同源策略, (嗯嗯, 我知道[这个名字], 但我不知道它的内涵)~~~ 。一起来看看
(developer.mozilla.org/zh-CN/docs/…)
同源策略是一个重要的安全策略,它用于限制一个 origin(域, 协议和端口)的文档或者它加载的脚本如何能与另一个源的资源进行交互。++它能帮助阻隔恶意文档,减少可能被攻击的媒介。
那么它的目的是什么呢?
同源策略的目的及限制
浏览器的同源策略目的是为了保护用户的信息安全,为了防止恶意网站窃取用户在浏览器上的数据
限制:
- Cookie,LocalStorage,和 IndexDB 访问受限
- 无法操作跨域 DOM(常见的如 iframe)
- js 发起的 XHR 和 Fetch 请求受限
确切通俗的说, 浏览器的同源策略是为了包含我们的隐私, 具体的可以去下面看一看 https://www.zhihu.com/question/25427931
那么什么是我们所说的同源?
刚才,我们提到了origin, 同源就是指两个 URL 的协议,域名和端口保持一致,就算是同源, 而这三者中有一个不同就算是跨域。
协议://域名:端口号
当你在你的网址(一个域), 去访问另外一个不同源的服务的资源的时候, 就会给我们报一个跨域的错误
但是当我们去看请求头的时候,我们会发现其实, 请求是成功的!
tva4.sinaimg.cn/large/006xV…
那么, 浏览器是如何处理我们的这个请求呢?
跨域请求的发出和处理
不同源请求就是跨域请求, 那么浏览器是如何处理它的呢?
这就不得不提到另外一个策略 ==》 CORS 跨域资源共享, 它是一种基于 HTTP 头的机制, 该机制通过允许服务器标示除了它自己以外的其他 origin 域, 这样浏览器就可以访问加载这些资源。跨域资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求()。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
那我们什么时候去需要用 CORS 呢?
CORS 的功能概述
- 它新增了一组 HTTP 首部字段, 允许服务器声明那些源站通过浏览器有权限访问那些资源。
- 对那些++可能对服务器数据产生副作用的 HTTP 请求方法 (特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型 的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request) 从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。
- 上面的请求因此可以分为: 简单请求, 复杂请求
上面我们知道, CORS 跨域请求跨域分为两种类型
- 简单请求
- 请求方法:
GETHEADPOST - 请求头: Accept、Accept-Language、Content-Language、Content-Type
- 其中 Content-Type 限定为 :text/plain、multipart/form-data、application/x-www-form-urlencoded
- ... 看 MDN 文档
这些请求不会触发 CORS 的预检请求, 被允许跨域访问资源
请求过程:
在我们发送请求后, 浏览器会去查看这个请求是否是一个跨域请求, 如果是跨域请求的话,就会在请求头上面加一个 option 属性, 在 option 属性中添加本次请求来自那个源, 然后传递给服务器, 服务器通过这个值去看是否要同意这次请求。如果同意,就会返回带数据的正确请求。 如果不同意, 那么就会返回不带数据的正确请求。
那么两者都是 状态码为 200 的请求。浏览器如何去确认是否请求真正成功呢?
答案是: 浏览器会去查看响应的头信息, 如果头信息中没有包含 Access-Control-Allow-Origin字段, 那么它就会给我们报一个 cors 的错误。
这里用了一个掘金的请求信息
我们详细的看一下上面的响应头携带的信息
- access-control-allow-credentials: 该字段可选, 表示是否可以发送 cookie, 浏览器默认不会将当前地址的 Cookie 信息传输给后端(服务器), 以保证信息的安全性。需要进行设置。
- access-control-allow-origin: 这个字段是必须的,表示接受那些域名的请求(*为所有)
- 复杂请求
- 除了简单请求就全是复杂请求
复杂请求会进行一个预检请求, 类型为 options。
请求过程: 复杂请求会在正式请求之前进行一个预检请求, 类型为 options, 同样在请求头上携带 option 字段, 并且还携带两项 cors 特有内容==> 见下图(来自掘金);
- Access-Control-Request-Method – 该项内容是实际请求的种类,可以是 GET、POST 之类的简单请求,也可以是 PUT、DELETE 等等。
- Access-Control-Request-Headers – 该项是一个以逗号分隔的列表,当中是复杂请求所使用的头部。
预检请求其实就是对服务器的一种++权限请求++, 对应的服务器也会返回一个++预响应++, 只有响应成功,我们才会执行实际请求。 我们可以把复杂请求,想象成我们去别人家就要带走人家的一点东西!!!, 那么我们是不是需要先询问一下主人,可不可以?才可以带走或者放下。
那么为什么复杂请求有 预请求, 而简单请求没有呢? 这是因为, 复杂请求对应的内容的真实请求, 都需要服务器进行复杂处理, 如果我们发送过去,然后服务器处理完成后, 但是浏览器却因为跨域问题进行了拦截, 那么不就赔了夫人又折兵??, 所以相对于需要服务器进行复杂处理的请求, 就先发送一个 prefilght 的简单请求, 进行一个简单的询问。节约服务器的计算。 当预检请求通过之后发出正经的 HTTP 请求,还有一个就是一旦通过了预检请求就会,请求的时候就会跟简单请求,会有一个 Origin 头信息字段。
跨域? 怎么跨?
这里的话,就列举几个我比较喜欢的方法吧,
- 开发的时候,我们一般都使用 本地再起一个允许跨域请求的服务器(webpack server)作为一个跳板, 使用这个跳板服务器去代理请求。 因为同源策略是在浏览器中。
- 部署的时候, 我们跨域可以使用 nginx 进行反向代理, 对代理文件进行配置。
第一个的话, 可以去看我的 webpack 总结, 第二个的话, 可以去看我的 。。。(还没写)