我正在尝试从 HP Alm 的 REST API 中获取一些数据。它适用于一个小的 curl 脚本——我得到了我的数据。
现在使用 JavaScript、fetch 和 ES6(或多或少)似乎是一个更大的问题。我不断收到此错误消息:
Fetch API 无法加载。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问源“http://127.0.0.1:3000”。响应的 HTTP 状态代码为 501。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。
我知道这是因为我试图从本地主机中获取该数据,并且解决方案应该使用 Cross-Origin Resource Sharing (CORS)。我以为我确实做到了,但不知何故,它要么忽略了我在标题中写的内容,要么问题出在其他问题上。
那么,是否存在实施问题?我做错了吗?不幸的是,我无法检查服务器日志。我真的有点卡在这里。
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 插件,但随后我收到另一条错误消息:
当请求的凭据模式为“包含”时,响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“*”。因此,不允许访问源“http://127.0.0.1:3000”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
这个答案涵盖了很多领域,因此分为三个部分:
如何使用 CORS 代理来避免“No Access-Control-Allow-Origin 标头”问题
如何避免 CORS 预检
如何解决“Access-Control-Allow-Origin 标头不能是通配符”问题
如何使用 CORS 代理来避免“No Access-Control-Allow-Origin 标头”问题
如果您不控制前端代码向其发送请求的服务器,并且该服务器的响应问题只是缺少必要的 Access-Control-Allow-Origin
标头,您仍然可以通过发出请求来使事情正常进行通过 CORS 代理。
您可以使用 https://github.com/Rob--W/cors-anywhere/ 中的代码轻松运行自己的代理。
您还可以使用 5 个命令在 2-3 分钟内轻松地将自己的代理部署到 Heroku:
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 标头添加到响应中。将该响应连同添加的标头一起传递回请求的前端代码。
然后浏览器允许前端代码访问响应,因为带有 Access-Control-Allow-Origin
响应标头的响应是浏览器看到的。
即使请求是触发浏览器执行 CORS 预检 OPTIONS
请求的请求,这也有效,因为在这种情况下,代理还会发送使预检成功所需的 Access-Control-Allow-Headers
和 Access-Control-Allow-Methods
标头。
如何避免 CORS 预检
问题中的代码触发 CORS 预检 - 因为它发送 Authorization
标头。
https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有,Content-Type: application/json
标头也会触发预检。
“预检”是什么意思:在浏览器尝试问题代码中的 POST
之前,它首先向服务器发送一个 OPTIONS
请求,以确定服务器是否选择接收跨域 {1 } 具有 Authorization
和 Content-Type: application/json
标头。
它适用于一个小的 curl 脚本——我得到了我的数据。
要使用 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
请求的响应必须具有如下标头:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
如果 OPTIONS
响应不包含这些标头,则浏览器将停在那里并且永远不会尝试发送 POST
请求。此外,响应的 HTTP 状态码必须是 2xx——通常是 200 或 204。如果是任何其他状态码,浏览器就会停在那里。
问题中的服务器使用 501 状态代码响应 OPTIONS
请求,这显然意味着它试图表明它不支持 OPTIONS
请求。在这种情况下,其他服务器通常会以 405“方法不允许”状态代码进行响应。
因此,如果服务器以 405 或 501 或 200 或 204 以外的任何值响应该 OPTIONS
请求,或者如果没有使用那些必要的响应标头进行响应。
避免为问题中的案例触发预检的方法是:
如果服务器不需要授权请求标头,而是依赖于嵌入在 POST 请求正文中的身份验证数据或作为查询参数
如果服务器不要求 POST 正文具有 Content-Type: application/json 媒体类型,而是接受 POST 正文为 application/x-www-form-urlencoded 并带有名为 json (或其他)的参数,其值为JSON数据
如何解决“Access-Control-Allow-Origin 标头不能是通配符”问题
我收到另一条错误消息:当请求的凭据模式为“包含”时,响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“*”。因此,不允许访问源“http://127.0.0.1:3000”。 XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制。
对于具有凭据的请求,如果 Access-Control-Allow-Origin
标头的值为 *
,浏览器将不会让您的前端 JavaScript 代码访问响应。相反,这种情况下的值必须与前端代码的来源 http://127.0.0.1:3000
完全匹配。
请参阅 MDN HTTP 访问控制 (CORS) 文章中的 Credentialed requests and wildcards。
如果您控制要向其发送请求的服务器,则处理这种情况的常用方法是将服务器配置为获取 Origin
请求标头的值,并将其回显/反射回 { 2}响应头;例如,使用 nginx:
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(网络)服务器系统也有类似的方式来回显原始值。
我正在使用 Chrome。我也尝试使用那个 Chrome CORS 插件
该 Chrome CORS 插件显然只是简单地将 Access-Control-Allow-Origin: *
标头注入浏览器看到的响应中。如果插件更智能,它会做的是将假 Access-Control-Allow-Origin
响应标头的值设置为前端 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-*
标头是 response 标头。你永远不想在请求中发送它们。这样做的唯一效果是触发浏览器进行预检。
当客户端 URL 和服务器 URL 不匹配时会发生此错误,包括端口号。在这种情况下,您需要为跨源资源共享的 CORS 启用您的服务。
如果您要托管 Spring REST 服务,则可以在博文中找到它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
including the port number
:(
fetch()
选项中删除您的 mode: 'no-cores'
设置。除非您的请求中有 mode: 'cores'
,否则不会发送您的 JSON 正文。
出现问题是因为您在前端添加了以下代码作为请求标头:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
这些标头属于响应,而不是请求。所以删除它们,包括以下行:
headers.append('GET', 'POST', 'OPTIONS');
您的请求有 'Content-Type: application/json'
,因此触发了所谓的 CORS 预检。这导致浏览器使用 OPTIONS 方法发送请求。有关详细信息,请参阅 CORS preflight。
因此,在您的后端,您必须通过返回响应标头来处理此预检请求,其中包括:
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
当然,实际语法取决于您用于后端的编程语言。
在你的前端,它应该是这样的:
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));
}
就我而言,我使用以下解决方案。
前端或角度
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);
使用 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
只是我的两分钱......关于如何使用 CORS 代理来解决“无 Access-Control-Allow-Origin
标头”问题
对于那些在后端使用 php 的人来说,部署“CORS 代理”很简单:
创建一个名为 'no-cors.php' 的文件,其内容如下: $URL = $_GET['url']; echo json_encode(file_get_contents($URL));死();在您的前端,执行以下操作: fetch('https://example.com/no-cors.php' + '?url=' + url) .then(response=>{*/Handle Response/*}) `
添加 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));
}
CORS 问题的可能原因
检查您的服务器端访问标头:请参阅此链接
在浏览器中检查从服务器接收到的请求标头。下图显示了标题
如果您正在使用 fetch 方法并尝试访问跨域请求,请确保 mode:cors 存在。参考这个链接
有时,如果程序中存在问题,您也会遇到 CORS 问题,因此请确保您的代码正常工作。
确保在您的 API 中处理 OPTION 方法。
在 2021 年 12 月的 Chrome 97 中,不允许使用 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
上的 *
实施了相同的限制。如果您想恢复已被阻止的类似 *
的行为,您可能必须读取请求者的来源并将其作为预检响应中允许的来源返回。
在某些情况下,当存在其他一些无效凭据(例如:过期的 JWT)时,库可能会丢弃 Access-Control-Allow-Origin
响应标头。然后,浏览器显示“没有 'Access-Control-Allow-Origin' 标头存在”错误,而不是实际错误(在此示例中可能是过期的 JWT)。确保您的库不会丢弃标题并使客户感到困惑。
如果您的 API 是用 ASP.NET Core
编写的,请按照以下步骤操作:
安装 Microsoft.AspNetCore.Cors 包。
在 Startup.cs 文件的 ConfigureServices 方法中添加以下行: services.AddCors();
在文件 startup.cs 的 Configure 方法中添加以下行: app.UseCors(options => options.WithOrigins("http://localhost:8080") .AllowAnyHeader() .AllowAnyMethod());
确保在 - app.UseRouting(); 之后添加它参考下图(来自 MSDN)查看中间件顺序:https://i.stack.imgur.com/vQ4yT.png
对于 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);
如果您使用 Node.js 和 Express.js 作为后端和 React & Axios 作为 macOS 开发环境中的前端,您需要在 HTTPS 下运行双方。以下是最终对我有用的方法(经过数小时的深入研究和测试):
步骤 1:创建 SSL 证书
只需按照 How to get HTTPS working on your local development environment in 5 minutes 中的步骤操作即可。
你最终会得到几个文件作为运行 HTTPS 服务器和 React web 的凭据:
server.key & server.crt
您需要将它们复制到前端和后端的根文件夹中(在生产环境中,您可以考虑将它们复制到 ./ssh 文件夹中作为后端)。
第 2 步:后端设置
我阅读了很多建议使用'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 步:前端设置
这是来自 React 前端的 Axios 请求:
await axios.get(`https://localhost:8000/email/send`, {
params: { /* Whatever data you want to send */ },
headers: {
'Content-Type': 'application/json',
}
})
现在,您需要使用我们已经创建的 SSL 凭据以 HTTPS 模式启动您的 React Web。在您的 macOS 终端中输入:
HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start
此时,您从前端的 3000 端口从 HTTPS 连接发送请求,后端通过 8000 端口的 HTTPS 连接接收该请求。 CORS 应该对此感到满意;)
删除这个:
credentials: 'include',
就我而言,Web 服务器阻止了“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
我正在使用“webtier”/www/webtier/domains/[域名]/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>
我经常犯这个错误,正因为如此,我给你们做了一个“检查表”。
在您的项目中启用 CORS:如果您使用的是 Node.js(例如),您可以使用:npm install cors;从'cors'导入cors; app.use(cors());
您可以像这样手动设置标题(如果需要): 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,补丁,删除');
请记住在前端项目中将 http:// 添加到 API 链接,如果请求 URL 不是 HTTP 或 HTTPS,则某些浏览器(如 Chrome)不接受使用 CORS 的请求:http://localhost:3000/api
检查您的项目是否正在使用 proxy.config.js 文件。请参阅使用 Angular CLI 代理修复 CORS 错误。
}
?
当客户端从他的主机 username.companyname.com 调用我们的后端服务时,他曾经得到上述错误
需要两件事:
在发回响应时,发送键为 Access-Control-Allow-Origin 且值为 * 的标头: context.Writer.Header()["Access-Control-Allow-Origin"] = []string{"*" } // 避免 CORS 错误很重要使用 Go CORS 库将 AllowCredentials 设置为 false 并将 AllowAllOrigins 设置为 true。
对于 Node.js 和 Express.js 后端,我使用这个 :)
app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // 更新以匹配您将从 res 发出请求的域.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); });
更多详情:CORS on ExpressJS
使用下面的 npm 模块。这实际上挽救了生命。
https://www.npmjs.com/package/local-cors-proxy
您收到 CORS 错误,例如下面的 URL
https://www.google.co.in/search/list
成功安装 (local-cors-proxy) 全局 npm install -g local-cors-proxy
并设置代理 URL 即 CORS URL。例如,下面的 CORS 问题进入 localhost。因此,您需要为 CORS 问题域添加域名(https://www.google.co.in)和端口(--port 8010)。更多信息请查看链接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 完整网址:
http://localhost:8010/proxy/search/list
在您的本地项目中没有 CORS 问题响应。
localhost:5000
上运行的 Flutter Web 应用程序到 localhost:3000
上运行的 Node.js 服务器的请求。因此,在我的情况下,我应该在脚本中放置 "proxy": "lcp --proxyUrl http://localhost --port 3000"
并向 localhost:3000/proxy 发出请求,对吗?我仍然收到 'No 'Access-Control-Allow-Origin' header is present on the requested resource.'
错误 .. 我做错了什么还是它无法从 localhost 到 localhost?非常感谢
就我而言,我必须在所有现有中间件下方添加自定义标头中间件。我认为某些中间件可能与 Access-Control-Allow-Origin Header 冲突,并尝试根据自己的需要进行设置。
所以代码会是这样的->
app.use(cors());
....all other middleware here
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
...your routes
尝试在下面的代码中添加所有这些标头 在每个路由之前,您在应用程序中定义,而不是在路由之后
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`
https://i.stack.imgur.com/SOL5O.png
step3:以这种方式更新您的 fetch/axios api:
https://i.stack.imgur.com/0JL4i.png
我花了一段时间才弄清楚这一点。
不定期副业成功案例分享
Content-Type
和Access-Control-Allow-Origin
解决了这个问题 - 谢谢!https://cors-anywhere.herokuapp.com/
现在不再可用。客户端现在将收到403 Forbidden
错误 - 除非开发人员明确请求暂时通过。以下是公告:github.com/Rob--W/cors-anywhere/issues/301。我建议从答案中简单地删除cors-anywhere
引用,因为它不再有用。