首页 > 解决方案 > 用于 CORS 的 ExpressJS 设置和带有预检调用的会话

问题描述

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

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

在弄清楚这一点时,我基本上已经碰到了一堵石墙。我认为这是起源,但我已经定义了一个起源白名单,但这并没有帮助。

对我的配置有任何帮助将不胜感激

    // 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);
  });
  ...

预检请求标头 OPTION 调用

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

预检响应标头

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

邮政

Referrer Policy strict-origin-when-cross-origin

POST 请求标头

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

标签: expresssessioncors

解决方案


这个问题的答案原来是 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
}

推荐阅读