CORS 的 ExpressJS 设置和 session 预检调用

ExpressJS setup for CORS and session with preflight calls

我正在尝试设置一个服务器,它正在处理第 3 方请求,即它来自我们客户的域,但我需要通过此 Express 应用程序将请求代理到我们的 API。我需要在 session 中存储一些信息,为此我使用 Redis 缓存来存储实际数据。

我在尝试执行此操作时遇到了一系列 CORS 问题 运行。到目前为止,这是我得到的配置。它可以在我的本地开发机器上找到,在不同的端口上模拟两个服务器,但是当我部署时,我在 Preflight OPTION 上收到 CORS No Allow Credentials 错误,在随后的 POST 上收到 NS_ERROR_DOM_BAD_URI

我在解决这个问题时基本上遇到了困难。我以为是起源,但我已经定义了一个起源白名单,但没有帮助。

如果对我的配置有任何帮助,我们将不胜感激

    // set session cookie options, all environments
    const cookieOptions = {
      maxAge:   24 * 60 * 60 * 1000,  // 24 hours
      httpOnly: true,
      sameSite: 'none',   // sameSite and secure are necessary
      secure:   true      // to set 3rd party cookie for session
    }

    // express session configuration options
    const sessionOptions = {
      store:  new RedisStore({ client: redisClient }),
      secret: process.env.sessionKey,
      cookie: cookieOptions,
      resave: false,
      saveUninitialized: true,
    }

    app.set('trust proxy', 2)

    app.use( cors({
        origin:      validateCorsOrigins,  // also had the same error with this set to true
        methods:     'GET, PUT, PATCH, POST, DELETE, HEAD, OPTIONS',   // OPTIONS is necessary for preflight
        credentials: true     // client will have to set credentials as well
      })
    )

    app.use( session( sessionOptions ) )


    // POST endpoint
    app.post('/api/cars', (req, res, next) => {
      const session = req.session

      ....do some processing....
      session.vin = vin

      res.json({ cars: cars })
    })

我必须使用 trust proxy 设置,因为我要部署到 Docker 容器中。

客户代码

  var headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/json' });
  
  var payload = { <payload body here/> };
  
  var request = new Request(url, {
      method: 'POST',
      body: JSON.stringify(payload),
      mode: 'cors',
      credentials: 'include',
      headers: headers
  });
  const response = await fetch(request);
  const json = await response.json().catch(function (error) {
      console.log(error);
  });
  ...

预检请求Headers 选项调用

OPTIONS /api/cars HTTP/2
Host: proxyhost.example.com
User-Agent: Mozilla/5.0
Firefox/90.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Referer: https://localhost:5000/
Origin: https://localhost:5000
DNT: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Cache-Control: max-age=0

预检响应Headers

HTTP/2 200 OK
server: Kestrel
access-control-allow-headers: content-type
access-control-allow-origin: *
date: Sun, 20 Jun 2021 17:05:27 GMT
content-length: 0
X-Firefox-Spdy: h2

POST

Referrer Policy strict-origin-when-cross-origin

POST 请求 Headers

POST /api/cars undefined
Host: proxyhost.example.com
User-Agent: Mozilla/5.0  
Firefox/90.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://localhost:5000/
content-type: application/json
Origin: https://localhost:5000
Content-Length: 44
DNT: 1
Connection: keep-alive
Cookie: <cookie stuff/>
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

这个问题的答案原来是 Azure AppServices 覆盖我的应用程序的 CORS 设置的问题。如果定义了 AppServices CORS 设置,则它们将优先。您必须在 AppService 上禁用 CORS 才能使节点应用程序上的 CORS 设置生效。

$ az webapp cors remove --allowed-origins --resource-group "<resource_group_name>" --name "<app_service_name>" --slot "<slot_name>"

结果应该是:

{
  "allowedOrigins": [],
  "supportCredentials": false
}