我能够使用micro-cors绕过此问题。
我检查了its code,与我尝试通过手动使用res.setHeader
来自己做的事情没什么不同,很可能是我猜不到的东西。
尽管如此,我不明白为什么now.json
中的设置无法正常工作,我需要在无服务器功能中手动执行此操作。
无论如何,万一有人找到这篇文章,我最终会得到这样的东西:
import micro from "micro-cors";
function MyApi(req,res) {
if (req.method === "OPTIONS") {
return res.status(200).end();
}
// handling other requests normally after this
}
const cors = micro();
export default cors(MyApi);
我可能会再尝试使用一种自行编写的解决方案,以便更好地了解出了什么问题,并且还因为我不想额外依赖。
如果我这样做,将更新此答案。
编辑:在更深入地检查之后,我发现另一个问题是库express-jwt
在res
解析失败时专门更改了jwt
对象。 / p>
我有一个小型的中间件,它通过这样做破坏了一切:
await authValidateMiddleware(req,res);
当await
失败时,它中断了一切,因为express-jwt
在不知不觉中更改了res
标头(设置错误),然后我尝试设置了res
标头手动手动尝试自己正确处理错误,因此引发有关“多次更改res
标头”的问题。。
,
我遇到了类似的问题,并且通过将标题添加到路由中来解决了该问题,如下所示:
"routes": [
{
"src": ".*","methods": ["GET","POST","OPTIONS"],"headers": {
"Access-Control-Allow-Origin": "*","Access-Control-Allow-Headers": "Origin,X-Requested-With,Content-Type,Accept","Access-Control-Allow-Credentials": "true"
},"dest": "index.js","continue": true
},{
"src": "/user/login","methods": ["POST"],"dest": "index.js"
}
]
记住要添加continue: true
。
https://github.com/super-h-alt/zeit-now-cors-problems/blob/master/now.json
,
我处于几乎相同的情况。我在Vercel(Now)中有几个无服务器功能,我希望它们对任何来源的任何人都可用。我解决的方法类似于@illiteratewriter's answer。
首先,我在项目的根目录中有以下now.json
:
{
"routes": [
{
"src": "/api/(.*)",{
"src": "/api/(.*)","methods": ["OPTIONS"],"dest": "/api/cors"
}
]
}
这是两个路由配置的细分:
{
"src": "/api/(.*)","headers": {
"Access-Control-Allow-Origin": "*","Access-Control-Allow-Credentials": "true"
},"continue": true
}
匹配所有发送到/api/*
的请求。
将CORS标头应用于该路由,表示允许使用CORS。
应用CORS标头后,继续寻找其他路线匹配项。这使我们可以将CORS标头应用于 all 路由,而不必按路由进行。例如,现在/api/auth/login
和/api/main/sub/resource
都将应用CORS标头。
{
"src": "/api/(.*)","dest": "/api/cors"
}
此配置的作用是拦截所有HTTP/OPTIONS
请求(这是CORS飞行前检查),然后将它们重新路由到/api/cors
处的特殊处理程序。
路由配置细分的最后一点将我们引向/api/cors.ts
函数。该处理程序如下所示:
import {NowRequest,NowResponse} from '@now/node';
export default (req: NowRequest,res: NowResponse) => {
return res.status(200).send();
}
此处理程序所做的基本上是接受CORS飞行前OPTIONS
请求,并以200/OK
对其进行响应,向客户表示“是的,我们对CORS业务开放。”
,
我对CORS和Vercel无服务器功能有很多类似的问题。
经过很多尝试→失败过程后,我才找到解决方案。
解决方案
tldr
最简单的解决方案,只需使用micro-cors。
并具有类似的实现;
import { NowRequest,NowResponse } from '@now/node';
import microCors from 'micro-cors';
const cors = microCors();
const handler = (request: NowRequest,response: NowResponse): NowResponse => {
if (request.method === 'OPTIONS') {
return response.status(200).send('ok');
}
// handle incoming request as usual
};
export default cors(handler);
版本较长,但没有任何新的依赖项
使用vercel.json
处理请求标头
vercel.json
{
"headers": [
{
"source": "/.*","headers": [
{
"key": "Access-Control-Allow-Origin","value": "*"
},{
"key": "Access-Control-Allow-Headers","value": "X-Requested-With,Access-Control-Allow-Origin,X-HTTP-Method-Override,Authorization,Accept"
},{
"key": "Access-Control-Allow-Credentials","value": "true"
}
]
}
]
}
自我尝试后,上述设置中有 2个重要的键,
- 您必须将
Access-Control-Allow-Origin
设置为所需的内容
- 在
Access-Control-Allow-Headers
中,您必须在其值中包括 Access-Control-Allow-Origin
。
然后在无服务器功能中,您仍然还需要处理pre-flight request
/api/index.ts
const handler = (request: NowRequest,response: NowResponse): NowResponse => {
if (request.method === 'OPTIONS') {
return response.status(200).send('ok');
}
// handle incoming request as usual
};
我建议通读micro-cors中的代码,它是非常简单的代码,您可以在几分钟之内理解它的作用,这使我不必担心将其添加到我的依赖项中。
,
接受的答案对我不起作用。但是,现在vercel似乎具有updated their advice,其示例代码为:
const allowCors = fn => async (req,res) => {
res.setHeader('Access-Control-Allow-Credentials',true)
res.setHeader('Access-Control-Allow-Origin','*')
// another option
// res.setHeader('Access-Control-Allow-Origin',req.headers.origin);
res.setHeader('Access-Control-Allow-Methods','GET,OPTIONS')
res.setHeader(
'Access-Control-Allow-Headers','X-CSRF-Token,Accept,Accept-Version,Content-Length,Content-MD5,Date,X-Api-Version'
)
if (req.method === 'OPTIONS') {
res.status(200).end()
return
}
return await fn(req,res)
}
const handler = (req,res) => {
const d = new Date()
res.end(d.toString())
}
module.exports = allowCors(handler)
值得一提的是,我不确定res.end
和res.send
之间的区别,但是为了将响应实际吸收到前端(响应),我将handler
函数更改为:
const handler = (req,res) => {
const d = {data: "Hello World"};
res.send(d)
}
这使我能够以以下方式摄取React:
function getAPIHelloWorld () {
let connectStr = "/api"
fetch(connectStr)
.then(response => response.json())
.then(response => {console.log(response.data)})
.catch(err => console.error(err))
}