生产环境后端调用不同的服务引起跨域问题

jasmine 于 2024-03-04 发布

1.场景描述

后端老服务是单体服务集成security 新增加微服务,服务没有集成security,有跨域浏览器 老服务中有token验证,新服务中没有token验证

这样产生的一个问题就是,当浏览器调用新服务接口的时候,出现跨域问题

2. 问题排查过程

1)看下请求有没有到后端(没有)

2)用charls,看浏览器有没有发送OPTIONS请求(发送了)

3)对比原有正确的请求和新增接口跨域请求,返回的报文是否一致(不一致)

正确的报文

HTTP/1.1 200 
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://192.168.17.152:8000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type, token
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Sun, 07 Apr 2024 02:43:22 GMT
Keep-Alive: timeout=60
Proxy-Connection: keep-alive

有问题的报文:

HTTP/1.1 200 
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Content-Length: 0
Date: Sun, 07 Apr 2024 02:38:13 GMT
Keep-Alive: timeout=60
Proxy-Connection: keep-alive

4)模拟请求,发现旧项目的OPTIONS请求是security框架返回的,而新项目是CrosFilter返回的,所有两个不一样

3.问题原因

浏览器认为后端服务是有token凭据验证的,返回的报文中需要有Access-Control-Allow-Credentials: true,当有Access-Control-Allow-Credentials: true的时候Access-Control-Allow-Origin属性不能是*

旧项目OPTIONS请求返回时security框架返回 新项目是CrosFilter返回的,所以两者返回的不一样

实际是增加token产生的影响

4.解决方案

修改跨域Filter


import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 跨域请求处理
 */
@Slf4j
@WebFilter(filterName = "CrosFilter ", urlPatterns = "/*")
@Component
public class CrosFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse response = (HttpServletResponse) resp;

        String method1 = req.getMethod();
        System.out.println("method1:" + method1);

        String method = req.getHeader("Access-Control-Request-Method");
        String origin = req.getHeader("Origin");
        //解决跨域访问报错
//        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Origin", origin);
//        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Methods", method);
        //设置过期时间
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, token, Authorization");
        // 支持HTTP 1.1.
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        // 支持HTTP 1.0. response.setHeader("Expires", "0");
        response.setHeader("Pragma", "no-cache");

        response.setHeader("Access-Control-Allow-Credentials", "true");

        response.setHeader("X-Content-Type-Options", "nosniff");
        response.setHeader("X-XSS-Protection", "1; mode=block");
        response.setHeader("X-Frame-Options", "DENY");

        // 编码
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, resp);
    }

    @Override
    public void init(FilterConfig filterConfig) {
        log.info("跨域过滤器启动");
    }

    @Override
    public void destroy() {
        log.info("跨域过滤器销毁");
    }
}