随机发生,预检响应缺少允许标头

Posted

技术标签:

【中文标题】随机发生,预检响应缺少允许标头【英文标题】:Random occurrence with preflight response missing allow headers 【发布时间】:2020-04-25 13:11:29 【问题描述】:

这个常见错误是随机发生的:

OPTIONS https://api.cloudfunctions.net/api/graphql 404
Access to fetch at 'https://api.cloudfunctions.net/api/graphql' from origin 'https://website.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

我拥有的是一个带有部署在 Google Cloud Functions 上的 apollo 服务器和一个 react 客户端的 graphql 端点。在某些时候,客户端会在浏览器上抛出错误,但如果我尝试刷新或再次发送请求 2 或 3 次,它将起作用。

正在发送的预检请求标头:

:authority: api.cloudfunctions.net
:method: OPTIONS
:path: /api/graphql
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,id;q=0.8,ms;q=0.7
access-control-request-headers: content-type
access-control-request-method: POST
origin: https://website.com
referer: https://website.com/
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/79.0.3945.88 Safari/537.36

预期响应

access-control-allow-credentials: true
access-control-allow-headers: content-type
access-control-allow-methods: POST,OPTIONS
access-control-allow-origin: https://website.com
alt-svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000
content-length: 0
content-type: text/html
date: Wed, 08 Jan 2020 00:38:16 GMT
function-execution-id: 84et92k6mvd9
server: Google Frontend
status: 200
vary: Origin, Access-Control-Request-Headers
x-cloud-trace-context: 95d25375171148a66bc629cc41a79d05
x-powered-by: Express

随机失败响应

alt-svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000
cache-control: private
content-encoding: gzip
content-length: 140
content-security-policy: default-src 'none'
content-type: text/html; charset=utf-8
date: Wed, 08 Jan 2020 00:38:05 GMT
function-execution-id: 84etgky3im1k
server: Google Frontend
status: 404
x-cloud-trace-context: 77040d2c72304cad0d645480b6814f7f;o=1
x-content-type-options: nosniff
x-powered-by: Express

查看上面的失败响应有点意思,与成功响应相比,它缺少 access-control-allow-* 标头,但我再次不确定这是怎么发生的。

这是我的 cors 配置:

const corsConfig = 
  origin: ['https://website.com', 'http://localhost:3000'],
  methods: ['POST', 'OPTIONS'],
  credentials: true,
  optionsSuccessStatus: 200,


const app = express()
app
  .use(cors(corsConfig))
  .use(...)

...

apolloServer.applyMiddleware( app, cors: corsConfig )

根据周围的一些建议,我尝试了不同的设置,但有时仍然会发生错误:

在applyMiddleware中设置cors: false 删除cors 如上所示重复 cors 按照doc says添加app.options('*', cors())

这一切都发生在十分之一的情况下,有时是在用户打开网站后第一次请求,而其他时间是在用户浏览网站一段时间后。

【问题讨论】:

app .use(cors(corsConfig))之前有没有中间件或请求处理程序? 不,除非我在 app.options('*', cors()) 之前添加了它。 【参考方案1】:

我认为可能还有其他中间件会破坏您的 cors 设置。

您可以尝试为您的graphql 端点使用不同的路径,并将cors 仅应用于该路径。

apolloServer.applyMiddleware( app, path: '/graphql', cors: corsConfig );

或者,您可以尝试使用 express cors 中间件并从 apollo 服务器禁用 cors

【讨论】:

我已经完成了所有这些工作:路径默认为/graphql,并使用如上所示的 express cors 并通过将其设置为 false 来禁用 apollo cors。似乎其他中间件可能会导致问题,但我不知道它是什么以及为什么它并不总是发生 @spondbob 您是否尝试在 Google Cloud 之外运行您的服务器进行测试,看看这是否是由 Google Cloud 引起的。 还没有真正尝试过,但它在本地机器上工作正常从来没有遇到过这个问题。我也想知道位于我的客户端和 graphql 之间的 Google 前端服务器是否指向做其他事情但看不到这是如何发生的。【参考方案2】:

我使用apollo-server-cloud-functions 包来解决这个问题。只需按照此处 (https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-cloud-functions) 的说明进行操作,但不要使用 exports.handler = server.createHandler() 将其换成您自己的函数,如下所示:

exports.api = functions.https.onRequest(
  server.createHandler(
    cors: 
      origin: true,
      credentials: true
    
  )
);

这为我解决了!

【讨论】:

以上是关于随机发生,预检响应缺少允许标头的主要内容,如果未能解决你的问题,请参考以下文章

跨域资源共享错误:预检响应不允许标头

预检请求没问题,然后,经过身份验证,响应不包含允许 cors 标头

预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段内容类型

预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段 ...

根据 CORS 预检响应中的标头“Access-Control-Allow-Headers”,标头“内容类型”是不允许的

预检响应中的 Access-Control-Allow-Headers 不允许请求标头字段授权