我来试试这个复杂的主题。
什么是“来源”?
来源本身是一个主机的名称(方案、主机名和端口),例如https://www.google.com,或者可以是一个本地打开的文件file://等等。它是某物(例如一个网页)的起源所在。当你打开你的网络浏览器并访问https://www.google.com时,显示给你的网页的来源就是https://www.google.com。你可以在Chrome开发者工具的“安全”选项下看到这一点。
![](https://istack.dev59.com/oQUSz.webp)
如果您通过文件浏览器打开本地HTML文件(而不是通过服务器提供服务),同样适用。
![](https://istack.dev59.com/GIFWY.webp)
这与CORS问题有什么关系?
当你打开浏览器并访问https://website.example时,该网站的来源将是https://website.example。这个网站很可能只会获取图片、图标、js文件,并向https://website.example发起API调用,基本上它是从同一个服务器获取的。它正在对同一来源进行调用。
如果你打开浏览器并打开一个本地HTML文件,在该HTML文件中有JavaScript想要向Google发起请求,你会得到以下错误:
![](https://istack.dev59.com/RM2yz.webp)
同源策略告诉浏览器阻止跨域请求。在这个例子中,源为
null
的请求试图访问
https://www.google.com
(一个跨域请求)。浏览器不允许这样做,因为CORS策略设置了不允许跨域请求。
如果我的页面是从本地服务器提供的,同样的规则也适用。
![](https://istack.dev59.com/Ildn1.webp)
本地服务器示例
如果我们使用以下代码在 localhost:3000
上托管我们自己的本地 API 服务器:
const express = require('express')
const app = express()
app.use(express.static('public'))
app.get('/hello', function (req, res) {
res.send('Hello World');
})
app.listen(3000, () => {
console.log('alive');
})
打开一个HTML文件(该文件向localhost:3000服务器发出请求),从文件浏览器中打开该文件夹时,会出现以下错误:
![](https://istack.dev59.com/KYAnv.webp)
由于网页不是从本地服务器
localhost:3000
上提供的,并且通过文件浏览器访问的源与服务器 API 源不同,因此正在尝试进行跨源请求。浏览器由于 CORS 策略而停止此尝试。
但是,如果我们取消注释掉的那一行:
const express = require('express')
const app = express()
app.use(express.static('public'))
app.get('/hello', function (req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.send('Hello World');
})
app.listen(3000, () => {
console.log('alive');
})
现在再试一次:
![](https://istack.dev59.com/A48Qh.webp)
它能够工作,是因为发送HTTP响应的服务器现在包含了一个头部,声明允许跨域请求发送到服务器,这意味着浏览器会允许这种情况发生,因此不会出现错误。
只是为了明确,CORS策略是现代浏览器的安全功能,用于保护人们免受有害和恶意代码的侵害。
如何修复问题(以下其中一种方法)
- 将页面从与所进行请求的源相同的地方提供(同一主机)。
- 通过在响应头中明确声明允许接收跨域请求来允许服务器。
- 如果使用反向代理(如Nginx),请配置Nginx发送允许CORS的响应头。
- 不要使用浏览器。例如,使用cURL,它不关心浏览器那样的CORS策略,可以得到您想要的结果。
示例流程
以下内容摘自:跨域资源共享(CORS)
记住,同源策略告诉浏览器阻止跨域请求。当你想从不同的源获取公共资源时,提供资源的服务器需要告诉浏览器“这个请求来自的源可以访问我的资源”。浏览器会记住这个信息并允许跨域资源共享。
步骤1:客户端(浏览器)请求 当浏览器进行跨域请求时,浏览器会添加一个包含当前源(协议、主机和端口)的 Origin 头。
步骤2:服务器响应 在服务器端,当服务器看到这个头,并希望允许访问时,需要在响应中添加一个 Access-Control-Allow-Origin 头,指定请求的源(或 * 允许任何源)。
步骤3:浏览器接收响应 当浏览器看到带有适当的 Access-Control-Allow-Origin 头的响应时,浏览器允许共享响应数据给客户端站点。
更多链接
这里有另一个很好的答案,更详细地解释了发生的情况:
https://dev59.com/FWgv5IYBdhLWcg3wY_42#10636765