首页 > 解决方案 > 即使在 Express 和 Express 网关上启用 CORS 后,仍受 CORS 策略的限制

问题描述

我正在使用Express Gateway代理我的微服务。我从我的react应用程序中使用Axios. 但是,呼叫受到限制CORS Policy。我已经在快速网关和我的身份验证服务中启用了 CORS。我按照官方文档从Express Gateway 的链接和身份验证服务(Express App)的链接启用 CORS。这是我的代码。

快速网关 config.yml

policies:
  - log
  - proxy
  - jwt
  - rate-limit
  - request-transformer
  - cors

pipelines:
  authPipeline: 
    apiEndpoints: 
      - auth
    policies: 
      -
        cors:
          -
            action:
              origin: '*'
              methods: 'HEAD,PUT,PATCH,POST,DELETE'
              allowedHeaders: ['Content-Type', 'Authorization']
      - 
        log: 
          action:
            message: 'auth ${req.method}'
      - 
        proxy:
          action: 
            serviceEndpoint: di

身份验证服务 app.js

const cors = require('cors');
// Enabling CORS
const corsOptions = {
  origin: '*',
  methods: ['POST', 'GET', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}
app.use(cors(corsOptions));

当我尝试使用 Insomnia(像 Postman 这样的客户端)时,我从服务器返回的标头可以在下图中看到。

我从服务器获得的标头

我在浏览器控制台中收到此错误。

Access to XMLHttpRequest at 'http://127.0.0.1:8080/api/v1/users/login' from 
origin 'http://localhost:3000' has been blocked by CORS policy: Response to 
preflight request doesnt pass access control check: No 'Access-Control- 
Allow-Origin' header is present on the requested resource.

我不确定我错过了什么。如果您需要其他任何东西,请告诉我,我会尽快提供。每一次试图解释我的案例有什么问题的尝试都非常感谢。

编辑:添加 API 调用片段

const config = {
    headers: {
      'Content-Type': 'application/json',
    },
  };
const body = JSON.stringify({ email, password });
const res = await axios.post('http://127.0.0.1:8080/api/v1/users/login', body, config);

标签: node.jsreactjscorsmicroservicesexpress-gateway

解决方案


您的“方法”定义不正确。它需要采用 YAML 数组的形式:

methods: [ "HEAD", "PUT", "PATCH", "POST", "DELETE" ]

或者

methods:
- "HEAD"
- "PUT"
- "PATCH"
- "POST"
- "DELETE"

或者

methods:
- HEAD
- PUT
- PATCH
- POST
- DELETE

其他一切看起来都不错,尽管您可能希望将“来源”添加到 allowedHeaders 列表中。

更新 我已经对此做了一些进一步的测试,使用这个迷你快递服务器,然后在 Docker 上运行 API 网关和服务器(在 gateway.config.yml 中进行适当的主机名更改),一切正常,通过来自 localhost 的 curl 进行测试也来自浏览器。

var express = require('express')
var app = express()

// Enabling CORS
const cors = require('cors');
const corsOptions = {
  origin: '*',
  methods: ['POST', 'GET', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}
app.use(cors(corsOptions));

function addPath(path) {
  app.use(path, function(req, res, next) {
    const response = `Hello from ${req.method} ${path}`;
    console.log(response);
    res.send(response);
  });
}

addPath('/api/v1/users/*');
addPath('/api/v1/*');

const port = 5000;
app.listen(port, function () {
  console.log(`Example app listening on port ${port}`)
})

我唯一可以建议的另一件事是在 gateway.config.yml 中的 cors 策略条目之前添加另一条日志消息,如下所示:

- 日志:操作:消息:“传入(身份验证):${req.method} ${req.path} 请求 IP:${req.ip} 来源 ${req.headers.origin}”

并检查原产地的价值。如果它不是未定义的,请尝试在代理策略之前添加以下响应转换器(当然,将响应转换器添加到可用策略列表中)。我不得不这样做一两次,但我忘记了必要的情况,所以这是在黑暗中拍摄的。

  - response-transformer:
    - condition:
        name: expression
        expression: 'typeof req.headers.origin !== "undefined" && req.headers.origin === "http://localhost"'
      action:
        headers:
          add:
            access-control-allow-origin: '"http://localhost"'

推荐阅读