现象
-
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 请求头?
因为:
以下情况浏览器会带上 Origin
1、所有跨域请求
2、除了 GET
和 HEAD
请求外的同源请求
网友评论