Nginx Ingress跨域配置

当请求ACK集群服务时,报blocked by CORS policy错误,是因为浏览器只允许网页访问相同协议、域名和端口的资源。比如网站https://example.com无法直接访问不同域名的资源https://api.example.com。通过给Nginx Ingress配置注解(Annotations),启用跨域资源共享(CORS)策略,从而允许特定的跨域请求。

工作原理

CORS请求分为两种类型:简单请求和预检请求。简单请求可以直接发送,预检请求必须先获得许可才能发送主请求。

如果满足以下任何一种情况,系统将对请求执行预检:

  • 请求使用的是GETHEADPOST以外的方法。

  • 请求使用POST方法且 Content-Type 不是 text/plainapplication/x-www-form-urlencoded 或 multipart/form-data

  • 请求设置了自定义头部。

当浏览器向Nginx Ingress发出简单请求时,会发生以下过程:

  1. 浏览器将Origin头部添加到请求中。Origin头部包含相应资源的来源,例如Origin: https://example.com

  2. Nginx Ingress Controller将请求的HTTP方法以及Origin头部的值与CORS配置进行比较,查找匹配项。如果存在匹配项,将在响应中包含Access-Control-Allow-Origin头部。Access-Control-Allow-Origin头部包含初始请求的Origin头部的值。

  3. 浏览器接收响应并检查Access-Control-Allow-Origin值是否与原始请求的域名匹配。如果匹配,则请求成功。如果不匹配,或者响应中不存在 Access-Control-Allow-Origin头部,则请求失败。

预检请求首先执行以下步骤,成功后再执行与简单请求相同的过程:

  1. 浏览器发送一个OPTIONS请求,包含主请求的方法(Access-Control-Request-Method)和头部(Access-Control-Request-Headers)信息。

  2. Nginx Ingress根据CORS配置检查请求的方法和头部是否被允许。如果预检请求中的任何方法或标头值未包含在目标资源允许的方法和标头集合中,请求将失败,并且不会发送主请求。

操作步骤

步骤一:配置CORS

  1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择网络 > 路由

  3. 路由页面操作列中,单击YAML编辑

  4. 根据具体业务场景,配置Nginx Ingress。常用配置说明,请参考Nginx Ingress Controller中常用CORS配置

携带凭证或Cookie的跨域场景

适用于常见的前后端分离场景:前端应用(https://example.comhttps://app.example.com)需要携带CookieAuthorization请求头等凭证访问后端API(https://api.example.com)。

YAML中添加以下示例中annotations配置内容。示例为example.comapp.example.com源域的GETPOST等方法开启跨域访问。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress-secure
  annotations:
    # 启用 CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    # 允许携带凭证(如 Cookie、Authorization 请求头)
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    # 精确指定允许发起跨域请求的来源域。严禁在凭证模式下使用 "*"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com, https://app.example.com"
    # 允许的 HTTP 方法
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
    # 允许的请求头,必须包含业务所需的自定义头(如 Authorization)
    nginx.ingress.kubernetes.io/cors-allow-headers: "Content-Type, Authorization"
    # 指定哪些自定义响应头字段暴露给前端
    nginx.ingress.kubernetes.io/cors-expose-headers: "X-Request-ID, Content-Length, Content-Range" 
    # 预检请求最大缓存时长(示例值86400秒,即24小时)	
    nginx.ingress.kubernetes.io/cors-max-age: "86400"
...

无需凭证的跨域场景

适用于公开、只读、无需任何身份验证的请求场景。

YAML中添加以下annotations配置内容。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress-secure
  annotations:
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"
    # 当 origin 为 "*" 时,credentials 必须为 false
    nginx.ingress.kubernetes.io/cors-allow-credentials: "false"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, HEAD"
...

步骤二:验证跨域配置

使用curl模拟浏览器发送OPTIONS预检请求。

curl -i -X OPTIONS 'https://api.example.com/your/path' \
  -H 'Origin: https://app.example.com' \
  -H 'Access-Control-Request-Method: POST' \
  -H 'Access-Control-Request-Headers: Content-Type, Authorization'

预期输出:正常情况应返回一个 2xx 的状态码(通常是 204 No Content 或 200 OK)。

HTTP/2 204
date: Fri, 12 Sep 2025 03:51:12 GMT
access-control-allow-origin: https://example.com, https://app.example.com
access-control-allow-credentials: true
access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS
access-control-allow-headers: Content-Type, Authorization

检查响应头中 access-control-allow-* 各项的值,是否与 Ingress 资源中配置的 nginx.ingress.kubernetes.io/cors-* 值一致。

Nginx Ingress Controller中常用CORS配置

注解

描述

关联HTTP

示例

nginx.ingress.kubernetes.io/enable-cors

是否启用CORS策略。

nginx.ingress.kubernetes.io/enable-cors: "true"

nginx.ingress.kubernetes.io/cors-allow-origin

哪些域可以访问资源(可配置多个域)。

Access-Control-Allow-Origin

nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"

nginx.ingress.kubernetes.io/cors-allow-methods

允许的方法类型,例如GET、POST、PUT等。

Access-Control-Allow-Methods

nginx.ingress.kubernetes.io/cors-allow-methods: "GET, PUT, POST, DELETE, PATCH, OPTIONS"

nginx.ingress.kubernetes.io/cors-allow-headers

允许的自定义请求头字段。

Access-Control-Allow-Headers

nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range"

nginx.ingress.kubernetes.io/cors-allow-credentials

是否可以发送带有凭证的请求(如Cookie、HTTP认证信息)。

Access-Control-Allow-Credentials

nginx.ingress.kubernetes.io/cors-allow-credentials: "true"

nginx.ingress.kubernetes.io/cors-expose-headers

哪些响应头可以在浏览器中访问。

此注解需要 Nginx Ingress Controller v0.44 或更高版本

Access-Control-Expose-Headers

nginx.ingress.kubernetes.io/cors-expose-headers: "Content-Length,Content-Range"

nginx.ingress.kubernetes.io/cors-max-age

浏览器缓存预检请求结果的最大时间(单位:秒),较长的缓存时间可减少预检请求频率。如对安全性要求更高,可适当调低此值。

Access-Control-Max-Age

nginx.ingress.kubernetes.io/cors-max-age: "86400"

常见问题

配置完成后,仍出现跨域访问报错,如何排查?

检查浏览器开发者工具中的网络请求或 Nginx Ingress Controller 的日志,核实请求的来源域(Origin)、请求方法和请求头等,确认它们是否在 Ingress 的 CORS 允许范围内。

以下示例为典型的跨域报错输出。请求使用了POST方法,但该方法未在Access-Control-Allow-Methods响应头中被允许。

  • Method POST is not allowed by Access-Control-Allow-Methods in preflight response

  • Access to fetch at 'https://api.example.com/data' from origin 'https://app.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: xxxx.

在设置了nginx.ingress.kubernetes.io/cors-allow-credentials: "true"后,是否允许将nginx.ingress.kubernetes.io/cors-allow-origin配置为"*"?

不允许。这是由W3C规范和浏览器安全策略强制规定的。当一个请求需要携带凭证(如 Cookie)时,服务器必须明确指定它信任的来源域,而不能使用通配符 *。这是为了防止任何恶意网站都能利用用户的登录凭证向服务器发起请求,从而避免潜在的安全风险。

如何为同一域名下的不同路径(例如 /api/public/*/api/private/*)设置不同的 CORS 策略?

Nginx Ingress 的 CORS 注解是 Ingress 资源级别的,不支持路径级配置。标准做法是为需要不同 CORS 策略的路径组创建独立的 Ingress 资源。例如,创建一个 api-public-ingress.yaml 和一个 api-private-ingress.yaml,并为它们分别设置不同的 CORS 注解。

客户端如何获取服务端返回的自定义响应头?

默认情况下,浏览器在处理跨域请求时只能访问标准的响应头,包括Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。服务端返回的任何自定义头字段(如X-Request-ID),在没有配置的情况下,对客户端JavaScript都是不可见的。

nginx.ingress.kubernetes.io/cors-expose-headers注解用于设置Access-Control-Expose-HeadersHTTP响应头,以决定哪些非标准响应头字段可以通过客户端的JavaScript代码获取。具体配置,请参考携带凭证或Cookie的跨域场景

相关文档