我将尝试一下这个复杂的主题。
What is origin?
起源本身是主机的名称(方案、主机名和端口),例如https://www.google.com
或者可以是本地打开的文件file://
等等。这是某些东西(例如网页)的起源地。当您打开网络浏览器并转到https://www.google.com
,向您显示的网页的来源是https://www.google.com
。您可以在 Chrome 开发工具中看到这一点Security
:
如果您通过文件资源管理器(不通过服务器提供服务)打开本地 HTML 文件,则同样适用:
这有什么关系CORS issues?
当您打开浏览器并转到https://website.example
,该网站的起源是https://website.example
。该网站将最有可能的只是获取图像、图标、js 文件并进行 API 调用https://website.example
,基本上它正在调用与其提供服务的同一服务器。它正在对同源进行调用.
例如,如果您打开网络浏览器并打开本地 HTML 文件,并且该 HTML 文件中存在 JavaScript 想要向 Google 发出请求,您会收到以下错误:
同源策略告诉浏览器阻止跨域请求。在本例中,原点null
正在尝试请求https://www.google.com
(a 跨域请求)。浏览器将不允许这样做,因为设置了 CORS 策略,并且该策略不允许跨域请求。
如果我的页面是从本地主机上的服务器提供的,同样适用:
本地主机服务器示例
如果我们托管自己的 localhost API 服务器,运行在localhost:3000
使用以下代码:
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');
})
并打开一个 HTML 文件(该文件向localhost:3000
从文件资源管理器中访问 server) 目录将会发生以下错误:
由于该网页不是由本地主机服务器提供的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');
})
现在再试一次:
它可以工作,因为发送 HTTP 响应的服务器现在包含一个标头,表明跨源请求发生在服务器上是可以的,这意味着浏览器将允许它发生,因此不会出现错误。
需要明确的是,CORS 策略是现代浏览器的安全功能,旨在保护人们免受有害和恶意代码的侵害。
如何解决问题(以下之一)
- 从与您发出的请求所在的同一源(同一主机)提供页面服务。
- 通过在响应标头中明确说明,允许服务器接收跨源请求。
- 如果使用反向代理(例如 Nginx),请将 Nginx 配置为发送允许 CORS 的响应标头。
- 不要使用浏览器。例如,使用 cURL,它不像浏览器那样关心 CORS 策略,并且会为您提供您想要的内容。
流程示例
以下摘自:跨域资源共享 (CORS)
请记住,同源策略告诉浏览器阻止
跨域请求。当你想从某个地方获取公共资源时
不同的来源,资源提供服务器需要告诉
浏览器“请求的来源可以访问我的
资源”。浏览器会记住这一点并允许跨源资源
分享。
-
步骤1:客户端(浏览器)请求当浏览器发出跨域请求时,浏览器会添加一个 Origin 标头,其中包含
当前来源(方案、主机和端口)。
-
步骤 2:服务器响应 在服务器端,当服务器看到此标头并想要允许访问时,需要添加一个
响应的 Access-Control-Allow-Origin 标头指定
请求来源(或 * 允许任何来源。)
-
步骤 3:浏览器接收响应 当浏览器看到带有适当 Access-Control-Allow-Origin 标头的响应时,
浏览器允许与客户端站点共享响应数据。
更多链接
这是另一个很好的答案,更详细地说明了正在发生的事情:https://stackoverflow.com/a/10636765/1137669