请求的资源上不存在 'Access-Control-Allow-Origin' header — 尝试从 REST API 获取数据时
No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API
我正在尝试从 HP Alm 的 REST API 中获取一些数据。它与一个小的 curl 脚本一起工作得很好——我得到了我的数据。
现在用 JavaScript、fetch 和 ES6(或多或少)来做这件事似乎是一个更大的问题。我不断收到此错误消息:
Fetch API cannot load . Response to preflight request doesn't
pass access control check: No 'Access-Control-Allow-Origin' header is
present on the requested resource. Origin 'http://127.0.0.1:3000' is
therefore not allowed access. The response had HTTP status code 501.
If an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled.
我知道这是因为我试图从我的本地主机中获取该数据,解决方案应该使用 Cross-Origin Resource Sharing (CORS)。我以为我真的这样做了,但不知何故它要么忽略了我在 header 中写的内容,要么是其他问题。
那么,是否存在实施问题?我做错了吗?不幸的是,我无法检查服务器日志。我真的有点卡在这里。
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
我正在使用 Chrome。我也尝试使用那个 Chrome CORS 插件,但是我收到了另一条错误消息:
The value of the 'Access-Control-Allow-Origin' header in the response
must not be the wildcard '*' when the request's credentials mode is
'include'. Origin 'http://127.0.0.1:3000' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
这个答案涵盖了很多方面,所以分为三个部分:
- 如何使用 CORS 代理来避免 “否 Access-Control-Allow-Origin header” 问题
- 如何避免 CORS 预检
- 如何解决“Access-Control-Allow-Origin header不能是通配符”问题
如何使用CORS代理来避免“没有Access-Control-Allow-Originheader”问题
如果您不控制您的前端代码向其发送请求的服务器,而该服务器的响应问题只是缺少必要的 Access-Control-Allow-Origin
header,您通过 CORS 代理发出请求,仍然可以让事情正常进行。
您可以使用来自 https://github.com/Rob--W/cors-anywhere/ 的代码轻松地 运行 您自己的代理。
您还可以在 2-3 分钟内轻松地将自己的代理部署到 Heroku,使用 5 个命令:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
在 运行 执行这些命令后,您最终会得到自己的 CORS Anywhere 服务器 运行,例如 https://cryptic-headland-94862.herokuapp.com/
。
现在,在您的请求 URL 前加上代理的 URL:
https://cryptic-headland-94862.herokuapp.com/https://example.com
添加代理 URL 作为前缀会导致通过您的代理发出请求,其中:
- 将请求转发给
https://example.com
。
- 收到来自
https://example.com
的回复。
- 将
Access-Control-Allow-Origin
header 添加到响应中。
- 将添加了 header 的响应传递回请求前端代码。
然后浏览器允许前端代码访问响应,因为带有 Access-Control-Allow-Origin
响应 header 的响应是浏览器看到的。
即使请求是触发浏览器执行 CORS 预检 OPTIONS
请求的请求,这也有效,因为在这种情况下,代理还会发送 Access-Control-Allow-Headers
和 Access-Control-Allow-Methods
headers 需要使预检成功。
如何避免 CORS 预检
问题中的代码触发了 CORS 预检——因为它发送了 Authorization
header.
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有它,Content-Type: application/json
header 也会触发预检。
preflight是什么意思:浏览器在试题代码中的POST
之前,先向服务器发送OPTIONS
请求,判断服务器是否opting-in 到收到一个 cross-origin POST
有 Authorization
和 Content-Type: application/json
headers.
It works pretty well with a small curl script - I get my data.
要使用 curl
进行正确测试,您必须模拟浏览器发送的预检 OPTIONS
:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
…https://the.sign_in.url
替换为您实际的 sign_in
URL。
浏览器需要从那个 OPTIONS
请求得到的响应必须有 header 这样的:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
如果 OPTIONS
响应不包含那些 headers,浏览器将停在那里并且永远不会尝试发送 POST
请求。此外,响应的 HTTP 状态代码必须是 2xx——通常为 200 或 204。如果是任何其他状态代码,浏览器将立即停止。
问题中的服务器使用 501 状态代码响应 OPTIONS
请求,这显然意味着它试图表明它不支持 OPTIONS
请求。在这种情况下,其他服务器通常会响应 405“方法不允许”状态代码。
因此,如果服务器使用 405 或 501 响应 OPTIONS
请求,您将永远无法从前端 JavaScript 代码直接向该服务器发出 POST
请求或除 200 或 204 之外的任何其他内容,或者如果没有响应这些必要的响应 headers.
避免为问题中的案例触发预检的方法是:
- 如果服务器不需要
Authorization
请求 header,而是依赖于 POST
请求的 body 中嵌入的身份验证数据,或者作为查询参数
- 如果服务器不要求
POST
body 具有 Content-Type: application/json
媒体类型,而是接受 POST
body 作为 application/x-www-form-urlencoded
带有一个名为 json
(或其他)的参数,其值为 JSON data
如何解决“Access-Control-Allow-Origin header不能是通配符”问题
I am getting another error message:
The value of the 'Access-Control-Allow-Origin' header in the response
must not be the wildcard '*' when the request's credentials mode is
'include'. Origin 'http://127.0.0.1:3000
' is therefore not allowed
access. The credentials mode of requests initiated by the
XMLHttpRequest is controlled by the withCredentials attribute.
对于具有凭据的请求,如果 Access-Control-Allow-Origin
header 的值为 *
,浏览器将不允许您的前端 JavaScript 代码访问响应。相反,这种情况下的值必须与您的前端代码的来源完全匹配,http://127.0.0.1:3000
.
请参阅 MDN HTTP 访问控制 (CORS) 文章中的 Credentialed requests and wildcards。
如果您控制要向其发送请求的服务器,处理这种情况的常用方法是将服务器配置为采用 Origin
请求 header 的值,并且echo/reflect 即返回值 Access-Control-Allow-Origin
响应 header;例如,使用 nginx:
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(网络)服务器系统具有类似的方式来回显原始值。
I am using Chrome. I also tried using that Chrome CORS Plugin
那个 Chrome CORS 插件显然只是简单地注入了一个 Access-Control-Allow-Origin: *
header 进入浏览器看到的响应。如果插件更聪明,它会做的是将那个假 Access-Control-Allow-Origin
响应 header 的值设置为前端 JavaScript 代码 http://127.0.0.1:3000
的实际来源。
因此请避免使用该插件,即使是用于测试。这只是一种干扰。要测试在没有浏览器过滤的情况下从服务器获得的响应,最好使用上面的 curl -H
。
就问题中 fetch(…)
请求的前端 JavaScript 代码而言:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
删除这些行。 Access-Control-Allow-*
header 是 响应 header。您永远不想在请求中发送它们。唯一的作用是触发浏览器进行预检。
当客户端 URL 和服务器 URL 不匹配时会出现此错误,包括端口号。在这种情况下,您需要为跨源资源共享的 CORS 启用您的服务。
如果您正在托管 Spring REST 服务,那么您可以在博客中找到它 post CORS support in Spring Framework.
如果您使用 Node.js 服务器托管服务,则
- 停止 Node.js 服务器。
npm install cors --save
- 将以下行添加到您的 server.js
const cors=require("cors");
const corsOptions ={
origin:'*',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
}
app.use(cors(corsOptions)) // Use this after the variable declaration
删除这个:
credentials: 'include',
使用 dataType: 'jsonp'
对我有用。
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function
我正在使用 Spring REST,我解决了将 AllowedMethods 添加到 WebMvcConfigurer 中的问题。
@Value( "${app.allow.origins}" )
private String allowOrigins;
@Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println("allow origin: " + allowOrigins);
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//.allowedOrigins("http://localhost")
.allowedOrigins(allowOrigins)
.allowedMethods("PUT", "DELETE","GET", "POST");
}
};
}
出现问题是因为您在 front-end 中添加了以下代码作为 request header:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
那些 header 属于 响应 ,而不是请求。所以 删除 它们,包括行:
headers.append('GET', 'POST', 'OPTIONS');
您的请求已 'Content-Type: application/json'
,因此触发了所谓的 CORS 预检。这导致浏览器使用 OPTIONS 方法发送请求。有关详细信息,请参阅 CORS preflight。
因此,在您的 back-end 中,您必须通过返回响应 header 来处理此预检请求,其中包括:
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
当然,实际语法取决于您在 back-end 中使用的编程语言。
在你的front-end中应该是这样的:
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed: ' + error.message));
}
只是我的两分钱...关于 如何使用 CORS 代理解决“没有 Access-Control-Allow-Origin
header” 问题
对于那些在后端使用 php 的人来说,部署“CORS 代理”非常简单:
创建一个名为 'no-cors.php' 的文件,内容如下:
$URL = $_GET['url'];
echo json_encode(file_get_contents($URL));
die();
在您的前端,执行如下操作:
fetch('https://example.com/no-cors.php' + '?url=' + url)
.then(response=>{*/Handle Response/*})`
就我而言,网络服务器阻止了“OPTIONS”方法
检查您的网络服务器的选项方法
- 阿帕奇:https://www-01.ibm.com/support/docview.wss?uid=ibm10735209
- web 层:4.4.6 禁用选项方法https://docs.oracle.com/cd/E23943_01/web.1111/e10144/getstart.htm#HSADM174
- nginx: https://medium.com/@hariomvashisth/cors-on-nginx-be38dd0e19df
I'm using "webtier"
/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
改为
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
就我而言,我使用以下解决方案。
前端或Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
后端(我用PHP)
header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
如果您使用 Node.js and Express.js as the back-end and React & Axios as the front-end within a development environment in macOS, you need to run both sides under HTTPS。以下是最终对我有用的方法(经过数小时的深入研究和测试):
第 1 步:创建 SSL 证书
只需按照 How to get HTTPS working on your local development environment in 5 minutes.
中的步骤操作即可
您最终会得到几个文件,用作 运行 HTTPS 服务器和 React web 的凭据:
server.key & server.crt
需要拷贝到前后端根目录下(在生产环境下,可以考虑拷贝到文件夹中。 /ssh 用于 back-end).
第 2 步:Back-end 设置
我看了很多建议使用 'cors' 包甚至设置 ('Access-Control-Allow-Origin', '*') 的答案,这就像在说:“欢迎黑客访问我的网站”。就像这样:
import express from 'express';
const emailRouter = require('./routes/email'); // in my case, I was sending an email through a form in React
const fs = require('fs');
const https = require('https');
const app = express();
const port = 8000;
// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://localhost:3000");
next();
});
// Routes definition
app.use('/email', emailRouter);
// HTTPS server
const credentials = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(port, () => {
console.log(`Back-end running on port ${port}`);
});
如果你想测试 https 是否正常,你可以用下面的替换 httpsServer 常量:
https.createServer(credentials, (req: any, res: any) => {
res.writeHead(200);
res.end("hello world from SSL\n");
}).listen(port, () => {
console.log(`HTTPS server listening on port ${port}...`);
});
然后从网络浏览器访问它:https://localhost:8000/
第 3 步:Front-end 设置
这是来自 React 的 Axios 请求 front-end:
await axios.get(`https://localhost:8000/email/send`, {
params: { /* Whatever data you want to send */ },
headers: {
'Content-Type': 'application/json',
}
})
现在,您需要使用我们已经创建的 SSL 凭据以 HTTPS 模式启动您的 React 网络。在您的 macOS 终端中输入:
HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start
此时,您正在从您的 front-end 端口 3000 的 HTTPS 连接发送一个请求,由您的 back-end 在端口 8000 的 HTTPS 连接接收。 CORS 应该对此感到满意 ;)
对于 Node.js,如果您使用路由器,请确保在路由器之前添加 CORS。否则,您仍然会收到 CORS 错误。如下所示:
const cors = require('cors');
const userRouter = require('./routers/user');
expressApp = express();
expressApp.use(cors());
expressApp.use(express.json());
expressApp.use(userRouter);
添加 mode:no-cors
可以避免 API.
中的 CORS 问题
fetch(sign_in, {
mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
尝试在下面的代码中添加所有这些headers在每条路线之前,您在应用中定义,而不是在路线之后
app.use((req, res, next) =>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type,Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods','GET, POST, PATCH, DELETE');
如果您在将 React 应用程序部署到 netlify 时遇到此错误,请使用这些步骤。
第 1 步:在 React 应用程序的根文件夹中创建 netlify.toml
文件。
第 2 步:复制粘贴此代码:
`[[redirects]]
from = "/cors-proxy/*"
to = ":splat"
status = 200
force = true`
第 3 步:以这种方式更新您的 fetch/axios api:
我花了一段时间才弄明白。
使用下面的 npm 模块。这实际上挽救了生命。
https://www.npmjs.com/package/local-cors-proxy
您收到 CORS 错误,例如下面的 URL
https://www.google.co.in/search/list
成功安装(local-cors-proxy) global npm install -g local-cors-proxy
并设置代理URL 即CORS URL。
例如,下面的 CORS 问题进入本地主机。所以需要为CORS问题域添加域名(https://www.google.co.in)和端口(--port 8010)。
有关更多信息,请查看 link
https://www.npmjs.com/package/local-cors-proxy
lcp --proxyUrl https://www.google.co.in --port 8010
设置成功后会生成本地代理URL如下图
http://localhost:8010/proxy
在您的项目中使用该域名 API URL.
API满URL:
http://localhost:8010/proxy/search/list
在您的本地项目中获得没有 CORS 问题的响应。
如果你的API写在ASP.NET Core
,那么请按以下步骤操作:
安装 Microsoft.AspNetCore.Cors 包。
在文件 Startup.cs:
的 ConfigureServices 方法中添加以下行
services.AddCors();
在文件 Configure 方法中添加以下行 startup.cs:
app.UseCors(options =>
options.WithOrigins("http://localhost:8080")
.AllowAnyHeader()
.AllowAnyMethod());
确保在 - app.UseRouting();
之后添加此内容
参考下图(来自MSDN)查看中间件顺序:
https://i.stack.imgur.com/vQ4yT.png
CORS 问题的可能原因
检查您的 server-side 访问权限 headers: Refer to this link
在浏览器中检查从服务器收到的请求header。下图显示了 headers
如果您正在使用 fetch
方法并尝试访问 cross-origin 请求,请确保 mode:cors
存在。参考这个link
有时,如果程序中存在问题,您也会遇到 CORS 问题,因此请确保您的代码工作正常。
确保在 API 中处理 OPTION
方法。
在过去的几年里,我遇到过几次这个错误——似乎是在一个以前正常运行的网站上突然出现的。
我确定 Chrome(可能还有其他浏览器)可以 return 当服务器上发生一些不相关的错误阻止它处理 CORS 请求时出现此错误(并且在 return 出现 HTTP 500 错误之前)。
这些都是在.NET Core环境下发生的,不知道在其他环境下会不会发生
无论如何,如果您的代码之前运行正常,并且看起来正确,请考虑调试以找出是否存在其他错误,然后再疯狂地尝试解决实际上不存在的错误。
对于 Node.js and Express.js 后端,我使用这个 :)
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // Update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
更多详情:CORS on ExpressJS
当客户端从他的主机username.companyname.com调用我们的后端服务时,他曾经得到上述错误
需要两件事:
在发回response的同时,发送key为Access-Control-Allow-Origin,value为*
的header:
context.Writer.Header()["Access-Control-Allow-Origin"] = []string{"*"} // Important to avoid a CORS error
使用 Go CORS 库将 AllowCredentials 设置为 false,将 AllowAllOrigins 设置为 true。
这个错误我犯了很多次,正因如此,我对你们所有人做了一个“check-list”。
启用CORS on your project: If you're using Node.js(举例)你可以使用:
npm install cors;
import cors from 'cors';
app.use(cors());
您可以像这样手动设置 headers(如果需要的话):
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
记得在你的前端项目中添加http://到你的APIlink,有些浏览器像Chrome 如果请求 URL 不是 HTTP 或 HTTPS,则不要 接受使用 CORS 的请求:
http://localhost:3000/api
检查您的项目是否正在使用 proxy.config.js 文件。请参阅 Fixing CORS errors with Angular CLI proxy。
2021 年 12 月,Chrome97,Authorization: Bearer ...
是不允许的,除非它在 Access-Control-Allow-Headers
预检响应中(忽略 *
)。它产生了这个警告:
[Deprecation] authorization will not be covered by the wildcard symbol (*)
参见:Chrome Enterprise release notes, Chrome 97
它似乎也在 Access-Control-Allow-Origin
上对 *
实施了相同的限制。如果你想在它被阻止后恢复类似 *
的行为,你可能必须阅读请求者的来源并 return 它作为预检响应中允许的来源。
在某些情况下,当存在其他一些无效凭证(例如:过期的 JWT)时,图书馆可能会丢弃 Access-Control-Allow-Origin
响应 header。然后,浏览器显示“No 'Access-Control-Allow-Origin' header is present”错误而不是实际错误(在此示例中可能是过期的 JWT)。确保您的图书馆不会丢弃 header 并混淆客户。
我正在尝试从 HP Alm 的 REST API 中获取一些数据。它与一个小的 curl 脚本一起工作得很好——我得到了我的数据。
现在用 JavaScript、fetch 和 ES6(或多或少)来做这件事似乎是一个更大的问题。我不断收到此错误消息:
Fetch API cannot load . Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The response had HTTP status code 501. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
我知道这是因为我试图从我的本地主机中获取该数据,解决方案应该使用 Cross-Origin Resource Sharing (CORS)。我以为我真的这样做了,但不知何故它要么忽略了我在 header 中写的内容,要么是其他问题。
那么,是否存在实施问题?我做错了吗?不幸的是,我无法检查服务器日志。我真的有点卡在这里。
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
我正在使用 Chrome。我也尝试使用那个 Chrome CORS 插件,但是我收到了另一条错误消息:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
这个答案涵盖了很多方面,所以分为三个部分:
- 如何使用 CORS 代理来避免 “否 Access-Control-Allow-Origin header” 问题
- 如何避免 CORS 预检
- 如何解决“Access-Control-Allow-Origin header不能是通配符”问题
如何使用CORS代理来避免“没有Access-Control-Allow-Originheader”问题
如果您不控制您的前端代码向其发送请求的服务器,而该服务器的响应问题只是缺少必要的 Access-Control-Allow-Origin
header,您通过 CORS 代理发出请求,仍然可以让事情正常进行。
您可以使用来自 https://github.com/Rob--W/cors-anywhere/ 的代码轻松地 运行 您自己的代理。
您还可以在 2-3 分钟内轻松地将自己的代理部署到 Heroku,使用 5 个命令:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
在 运行 执行这些命令后,您最终会得到自己的 CORS Anywhere 服务器 运行,例如 https://cryptic-headland-94862.herokuapp.com/
。
现在,在您的请求 URL 前加上代理的 URL:
https://cryptic-headland-94862.herokuapp.com/https://example.com
添加代理 URL 作为前缀会导致通过您的代理发出请求,其中:
- 将请求转发给
https://example.com
。 - 收到来自
https://example.com
的回复。 - 将
Access-Control-Allow-Origin
header 添加到响应中。 - 将添加了 header 的响应传递回请求前端代码。
然后浏览器允许前端代码访问响应,因为带有 Access-Control-Allow-Origin
响应 header 的响应是浏览器看到的。
即使请求是触发浏览器执行 CORS 预检 OPTIONS
请求的请求,这也有效,因为在这种情况下,代理还会发送 Access-Control-Allow-Headers
和 Access-Control-Allow-Methods
headers 需要使预检成功。
如何避免 CORS 预检
问题中的代码触发了 CORS 预检——因为它发送了 Authorization
header.
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有它,Content-Type: application/json
header 也会触发预检。
preflight是什么意思:浏览器在试题代码中的POST
之前,先向服务器发送OPTIONS
请求,判断服务器是否opting-in 到收到一个 cross-origin POST
有 Authorization
和 Content-Type: application/json
headers.
It works pretty well with a small curl script - I get my data.
要使用 curl
进行正确测试,您必须模拟浏览器发送的预检 OPTIONS
:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
…https://the.sign_in.url
替换为您实际的 sign_in
URL。
浏览器需要从那个 OPTIONS
请求得到的响应必须有 header 这样的:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
如果 OPTIONS
响应不包含那些 headers,浏览器将停在那里并且永远不会尝试发送 POST
请求。此外,响应的 HTTP 状态代码必须是 2xx——通常为 200 或 204。如果是任何其他状态代码,浏览器将立即停止。
问题中的服务器使用 501 状态代码响应 OPTIONS
请求,这显然意味着它试图表明它不支持 OPTIONS
请求。在这种情况下,其他服务器通常会响应 405“方法不允许”状态代码。
因此,如果服务器使用 405 或 501 响应 OPTIONS
请求,您将永远无法从前端 JavaScript 代码直接向该服务器发出 POST
请求或除 200 或 204 之外的任何其他内容,或者如果没有响应这些必要的响应 headers.
避免为问题中的案例触发预检的方法是:
- 如果服务器不需要
Authorization
请求 header,而是依赖于POST
请求的 body 中嵌入的身份验证数据,或者作为查询参数 - 如果服务器不要求
POST
body 具有Content-Type: application/json
媒体类型,而是接受POST
body 作为application/x-www-form-urlencoded
带有一个名为json
(或其他)的参数,其值为 JSON data
如何解决“Access-Control-Allow-Origin header不能是通配符”问题
I am getting another error message:
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin '
http://127.0.0.1:3000
' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
对于具有凭据的请求,如果 Access-Control-Allow-Origin
header 的值为 *
,浏览器将不允许您的前端 JavaScript 代码访问响应。相反,这种情况下的值必须与您的前端代码的来源完全匹配,http://127.0.0.1:3000
.
请参阅 MDN HTTP 访问控制 (CORS) 文章中的 Credentialed requests and wildcards。
如果您控制要向其发送请求的服务器,处理这种情况的常用方法是将服务器配置为采用 Origin
请求 header 的值,并且echo/reflect 即返回值 Access-Control-Allow-Origin
响应 header;例如,使用 nginx:
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(网络)服务器系统具有类似的方式来回显原始值。
I am using Chrome. I also tried using that Chrome CORS Plugin
那个 Chrome CORS 插件显然只是简单地注入了一个 Access-Control-Allow-Origin: *
header 进入浏览器看到的响应。如果插件更聪明,它会做的是将那个假 Access-Control-Allow-Origin
响应 header 的值设置为前端 JavaScript 代码 http://127.0.0.1:3000
的实际来源。
因此请避免使用该插件,即使是用于测试。这只是一种干扰。要测试在没有浏览器过滤的情况下从服务器获得的响应,最好使用上面的 curl -H
。
就问题中 fetch(…)
请求的前端 JavaScript 代码而言:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
删除这些行。 Access-Control-Allow-*
header 是 响应 header。您永远不想在请求中发送它们。唯一的作用是触发浏览器进行预检。
当客户端 URL 和服务器 URL 不匹配时会出现此错误,包括端口号。在这种情况下,您需要为跨源资源共享的 CORS 启用您的服务。
如果您正在托管 Spring REST 服务,那么您可以在博客中找到它 post CORS support in Spring Framework.
如果您使用 Node.js 服务器托管服务,则
- 停止 Node.js 服务器。
npm install cors --save
- 将以下行添加到您的 server.js
const cors=require("cors");
const corsOptions ={
origin:'*',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
}
app.use(cors(corsOptions)) // Use this after the variable declaration
删除这个:
credentials: 'include',
使用 dataType: 'jsonp'
对我有用。
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function
我正在使用 Spring REST,我解决了将 AllowedMethods 添加到 WebMvcConfigurer 中的问题。
@Value( "${app.allow.origins}" )
private String allowOrigins;
@Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println("allow origin: " + allowOrigins);
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//.allowedOrigins("http://localhost")
.allowedOrigins(allowOrigins)
.allowedMethods("PUT", "DELETE","GET", "POST");
}
};
}
出现问题是因为您在 front-end 中添加了以下代码作为 request header:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
那些 header 属于 响应 ,而不是请求。所以 删除 它们,包括行:
headers.append('GET', 'POST', 'OPTIONS');
您的请求已 'Content-Type: application/json'
,因此触发了所谓的 CORS 预检。这导致浏览器使用 OPTIONS 方法发送请求。有关详细信息,请参阅 CORS preflight。
因此,在您的 back-end 中,您必须通过返回响应 header 来处理此预检请求,其中包括:
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
当然,实际语法取决于您在 back-end 中使用的编程语言。
在你的front-end中应该是这样的:
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed: ' + error.message));
}
只是我的两分钱...关于 如何使用 CORS 代理解决“没有 Access-Control-Allow-Origin
header” 问题
对于那些在后端使用 php 的人来说,部署“CORS 代理”非常简单:
创建一个名为 'no-cors.php' 的文件,内容如下:
$URL = $_GET['url']; echo json_encode(file_get_contents($URL)); die();
在您的前端,执行如下操作:
fetch('https://example.com/no-cors.php' + '?url=' + url) .then(response=>{*/Handle Response/*})`
就我而言,网络服务器阻止了“OPTIONS”方法
检查您的网络服务器的选项方法
- 阿帕奇:https://www-01.ibm.com/support/docview.wss?uid=ibm10735209
- web 层:4.4.6 禁用选项方法https://docs.oracle.com/cd/E23943_01/web.1111/e10144/getstart.htm#HSADM174
- nginx: https://medium.com/@hariomvashisth/cors-on-nginx-be38dd0e19df
I'm using "webtier"
/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
改为
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
就我而言,我使用以下解决方案。
前端或Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
后端(我用PHP)
header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
如果您使用 Node.js and Express.js as the back-end and React & Axios as the front-end within a development environment in macOS, you need to run both sides under HTTPS。以下是最终对我有用的方法(经过数小时的深入研究和测试):
第 1 步:创建 SSL 证书
只需按照 How to get HTTPS working on your local development environment in 5 minutes.
中的步骤操作即可您最终会得到几个文件,用作 运行 HTTPS 服务器和 React web 的凭据:
server.key & server.crt
需要拷贝到前后端根目录下(在生产环境下,可以考虑拷贝到文件夹中。 /ssh 用于 back-end).
第 2 步:Back-end 设置
我看了很多建议使用 'cors' 包甚至设置 ('Access-Control-Allow-Origin', '*') 的答案,这就像在说:“欢迎黑客访问我的网站”。就像这样:
import express from 'express';
const emailRouter = require('./routes/email'); // in my case, I was sending an email through a form in React
const fs = require('fs');
const https = require('https');
const app = express();
const port = 8000;
// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://localhost:3000");
next();
});
// Routes definition
app.use('/email', emailRouter);
// HTTPS server
const credentials = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(port, () => {
console.log(`Back-end running on port ${port}`);
});
如果你想测试 https 是否正常,你可以用下面的替换 httpsServer 常量:
https.createServer(credentials, (req: any, res: any) => {
res.writeHead(200);
res.end("hello world from SSL\n");
}).listen(port, () => {
console.log(`HTTPS server listening on port ${port}...`);
});
然后从网络浏览器访问它:https://localhost:8000/
第 3 步:Front-end 设置
这是来自 React 的 Axios 请求 front-end:
await axios.get(`https://localhost:8000/email/send`, {
params: { /* Whatever data you want to send */ },
headers: {
'Content-Type': 'application/json',
}
})
现在,您需要使用我们已经创建的 SSL 凭据以 HTTPS 模式启动您的 React 网络。在您的 macOS 终端中输入:
HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start
此时,您正在从您的 front-end 端口 3000 的 HTTPS 连接发送一个请求,由您的 back-end 在端口 8000 的 HTTPS 连接接收。 CORS 应该对此感到满意 ;)
对于 Node.js,如果您使用路由器,请确保在路由器之前添加 CORS。否则,您仍然会收到 CORS 错误。如下所示:
const cors = require('cors');
const userRouter = require('./routers/user');
expressApp = express();
expressApp.use(cors());
expressApp.use(express.json());
expressApp.use(userRouter);
添加 mode:no-cors
可以避免 API.
fetch(sign_in, {
mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
尝试在下面的代码中添加所有这些headers在每条路线之前,您在应用中定义,而不是在路线之后
app.use((req, res, next) =>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type,Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods','GET, POST, PATCH, DELETE');
如果您在将 React 应用程序部署到 netlify 时遇到此错误,请使用这些步骤。
第 1 步:在 React 应用程序的根文件夹中创建 netlify.toml
文件。
第 2 步:复制粘贴此代码:
`[[redirects]]
from = "/cors-proxy/*"
to = ":splat"
status = 200
force = true`
第 3 步:以这种方式更新您的 fetch/axios api:
我花了一段时间才弄明白。
使用下面的 npm 模块。这实际上挽救了生命。
https://www.npmjs.com/package/local-cors-proxy
您收到 CORS 错误,例如下面的 URL
https://www.google.co.in/search/list
成功安装(local-cors-proxy) global npm install -g local-cors-proxy
并设置代理URL 即CORS URL。
例如,下面的 CORS 问题进入本地主机。所以需要为CORS问题域添加域名(https://www.google.co.in)和端口(--port 8010)。
有关更多信息,请查看 link
https://www.npmjs.com/package/local-cors-proxy
lcp --proxyUrl https://www.google.co.in --port 8010
设置成功后会生成本地代理URL如下图
http://localhost:8010/proxy
在您的项目中使用该域名 API URL.
API满URL:
http://localhost:8010/proxy/search/list
在您的本地项目中获得没有 CORS 问题的响应。
如果你的API写在ASP.NET Core
,那么请按以下步骤操作:
安装 Microsoft.AspNetCore.Cors 包。
在文件 Startup.cs:
的 ConfigureServices 方法中添加以下行services.AddCors();
在文件 Configure 方法中添加以下行 startup.cs:
app.UseCors(options => options.WithOrigins("http://localhost:8080") .AllowAnyHeader() .AllowAnyMethod());
确保在 -
之后添加此内容app.UseRouting();
参考下图(来自MSDN)查看中间件顺序:
https://i.stack.imgur.com/vQ4yT.png
CORS 问题的可能原因
检查您的 server-side 访问权限 headers: Refer to this link
在浏览器中检查从服务器收到的请求header。下图显示了 headers
如果您正在使用
fetch
方法并尝试访问 cross-origin 请求,请确保mode:cors
存在。参考这个link有时,如果程序中存在问题,您也会遇到 CORS 问题,因此请确保您的代码工作正常。
确保在 API 中处理
OPTION
方法。
在过去的几年里,我遇到过几次这个错误——似乎是在一个以前正常运行的网站上突然出现的。
我确定 Chrome(可能还有其他浏览器)可以 return 当服务器上发生一些不相关的错误阻止它处理 CORS 请求时出现此错误(并且在 return 出现 HTTP 500 错误之前)。
这些都是在.NET Core环境下发生的,不知道在其他环境下会不会发生
无论如何,如果您的代码之前运行正常,并且看起来正确,请考虑调试以找出是否存在其他错误,然后再疯狂地尝试解决实际上不存在的错误。
对于 Node.js and Express.js 后端,我使用这个 :)
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // Update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
更多详情:CORS on ExpressJS
当客户端从他的主机username.companyname.com调用我们的后端服务时,他曾经得到上述错误
需要两件事:
在发回response的同时,发送key为Access-Control-Allow-Origin,value为
*
的header:context.Writer.Header()["Access-Control-Allow-Origin"] = []string{"*"} // Important to avoid a CORS error
使用 Go CORS 库将 AllowCredentials 设置为 false,将 AllowAllOrigins 设置为 true。
这个错误我犯了很多次,正因如此,我对你们所有人做了一个“check-list”。
启用CORS on your project: If you're using Node.js(举例)你可以使用:
npm install cors; import cors from 'cors'; app.use(cors());
您可以像这样手动设置 headers(如果需要的话):
app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authortization'); res.setHeader('Acces-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
记得在你的前端项目中添加http://到你的APIlink,有些浏览器像Chrome 如果请求 URL 不是 HTTP 或 HTTPS,则不要 接受使用 CORS 的请求:
http://localhost:3000/api
检查您的项目是否正在使用 proxy.config.js 文件。请参阅 Fixing CORS errors with Angular CLI proxy。
2021 年 12 月,Chrome97,Authorization: Bearer ...
是不允许的,除非它在 Access-Control-Allow-Headers
预检响应中(忽略 *
)。它产生了这个警告:
[Deprecation] authorization will not be covered by the wildcard symbol (*)
参见:Chrome Enterprise release notes, Chrome 97
它似乎也在 Access-Control-Allow-Origin
上对 *
实施了相同的限制。如果你想在它被阻止后恢复类似 *
的行为,你可能必须阅读请求者的来源并 return 它作为预检响应中允许的来源。
在某些情况下,当存在其他一些无效凭证(例如:过期的 JWT)时,图书馆可能会丢弃 Access-Control-Allow-Origin
响应 header。然后,浏览器显示“No 'Access-Control-Allow-Origin' header is present”错误而不是实际错误(在此示例中可能是过期的 JWT)。确保您的图书馆不会丢弃 header 并混淆客户。