【问题排查】Spring Cloud Gateway 返回 403 状态码

现象

GET 请求正常返回 POST 请求返回 403 Forbidden

gateway access 日志:

2022-01-11 11:56:52,488 : 10.0.16.132:15362 - - [11/Jan/2022:11:56:52 +0800] "GET /landing-page/experience-train-enroll/status?phoneNumber=15074470123 HTTP/1.1" 200 85 44 ms
2022-01-11 11:56:52,589 : 10.0.16.132:15362 - - [11/Jan/2022:11:56:52 +0800] "POST /landing-page/verify/code HTTP/1.1" 403 0 12 ms

请求路径为:【浏览器】==》【apache】==》【gateway】==》【后端 web 应用】

注意:【apache】会将接收到的 HTTPS 请求,转换为 HTTP 请求转发到【gateway】

跟踪 DefaultCorsProcessor 类的 process() 方法

package org.springframework.web.cors.reactive;
public class DefaultCorsProcessor implements CorsProcessor {
    public boolean process(@Nullable CorsConfiguration config, ServerWebExchange exchange) {
        // 1. 判断是否是跨域请求,如果不是直接返回 true
        if (!CorsUtils.isCorsRequest(request)) {
            return true;
        return handleInternal(exchange, config, preFlightRequest);
    protected boolean handleInternal(ServerWebExchange exchange,
            CorsConfiguration config, boolean preFlightRequest) {
        // 2. 获取请求头 Origin 的值
        String requestOrigin = request.getHeaders().getOrigin();
        String allowOrigin = checkOrigin(config, requestOrigin);
        // 4. 为 null 表示不满足条件,返回 403
        if (allowOrigin == null) {
            logger.debug("Reject: '" + requestOrigin + "' origin is not allowed");
            rejectRequest(response);
            return false;
        return true;
    // 3. 校验 requestOrigin 是否符合跨域的配置
    protected String checkOrigin(CorsConfiguration config, @Nullable String requestOrigin) {
        return config.checkOrigin(requestOrigin);
    // 5. 设置 http 响应状态码为 403
    protected void rejectRequest(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.FORBIDDEN);
public abstract class CorsUtils {
    // 跨域请求需要满足下面两个条件
    // 1. 包含 Origin 请求头
    // 2. request 的 schema:host:port 和 origin 一致
    public static boolean isCorsRequest(ServerHttpRequest request) {
        return request.getHeaders().containsKey(HttpHeaders.ORIGIN) && !isSameOrigin(request);

因为【apache】会把 HTTPS 协议请求转换为 HTTP 协议请求,而同源策略要求协议相同。

所以转化后的请求不再是同源请求,因此需要在 application.yml 文件中新增如下配置。

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: ["https://xxx-gamma.wumii.net"] # 此行配置是重点
            allowedMethods:
              - GET
              - POST
              - HEAD
              - PUT
              - DELETE
            allowedHeaders: '*'
            allowCredentials: true
        add-to-simple-url-handler-mapping: true

以支持跨域请求。

GET 请求为什么不会自动加上 Origin 请求头?