zoukankan      html  css  js  c++  java
  • No 'AccessControlAllowOrigin' header: 跨域问题踩坑记录

    前言

    前两周在服务器上部署一个系统时,遇到了跨域问题,这也不是第一次遇到跨域问题了,本来以为解决起来会很顺利,没想到解决过程中遇到了很多坑,所以觉得有必要写一篇博客记录一下这个坑。

    问题产生原因

    本来我们组的应用都有一个统一的网关服务进行接口请求转发,相关的配置都做好了,并不存在跨域问题。但前两周因为业务拓展,需要将部分应用拆分出来,部署到其他服务器上,这里面就包含我负责的两个应用。

    其中一个应用,因为是前后端不分离的项目,不存在跨域问题,所以部署起来比较顺利,直接打了一个jar包丢到服务器上面就顺利跑起来了。另一个项目则是前后端分离的项目,打jar包部署的过程倒时挺顺利的,可是当我把前端用nginx跑起来之后,却看到了类似下图这样一堆报错:

    这一看就是跨域问题了。

    解决过程

    1、修改nginx配置(不起作用)

    因为上一次遇到跨域问题,我就是通过nginx配置代理转发解决的,所以这次我首先想到的还是通过修改nginx配置来解决这个问题,所以我在nginx配置文件中添加了类似这样的配置:

    server{
        listen 8888;
        server_name  192.168.1.100;
    
        location /{
            proxy_pass http://192.168.1.100:8080;
        }
    
        location /api{
            proxy_pass http://192.168.1.100:8081; // 以api开头的接口请求,全部转发到这里
    }
    }

    然而,并不起作用。之后,我又在nginx配置文件中添加了一些关于请求头的设置,如下所示:

    add_header 'Access-Control-Allow-Headers' '*';
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,HEAD,PUT';
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true'

    同样的,也没有解决问题。到这里,我暂时放弃通过修改nginx配置文件来解决跨域问题的想法了。

    2、在后端代码中添加跨域处理配置

    关于如何在后端解决跨域问题,我之前也了解过,查了一下网上资料后,在代码中添加了一下两个配置类:

    WebMvcConfig:

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    /**
     * 全局处理接口跨域
     */
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
    //                .allowedOrigins("*")
                    // 这里网上的资料大部分说的是.allowedOrigins("*"),但因为我的springboot版本是2.5.5,
                    // allowCredentials为true时并且allowedOrigins不为空且为ALL(这个ALL就是*)时就会抛出异常
                    // 所以这里我设置的是.allowedOriginPatterns("*")
                    .allowedOriginPatterns("*")
                    .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                    .maxAge(3600)
                    .allowCredentials(true);
        }
    }

    CORSFilter:

    import org.springframework.stereotype.Component;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * 全局处理接口跨域
     */
    @Component
    public class CORSFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            Filter.super.init(filterConfig);
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.setHeader("Access-Control-Allow-Credentials", "true");
            res.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
            res.setHeader("Access-Control-Allow-Headers", "*");
            chain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
            Filter.super.destroy();
        }
    
    }

    本来以为加上了这两个配置类,这把绝对没问题了,可惜,问题依然没有解决。

    但这次部署上去之后,报错信息发生了变化,提示某些请求头(如client_id)没能成功跨域,这也给了我一些启发。

    3、最终的解决方案

    最后的最后,我将CORSFilter配置类中的:

    res.setHeader("Access-Control-Allow-Headers", "*");

    修改为:

    res.setHeader("Access-Control-Allow-Headers", "client_id, Authorization, Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");

    然后,打包部署上去,总算解决了跨域问题。

    总结

    这次问题解决后,我又查了一些资料,发现了以下两个知识点:

    1、Access-Control-Allow-Origin 请求头的设置是有一些特殊限制的,当 Access-Control-Allow-Credentials 的值为 true 时会导致Access-Control-Allow-Origin 无法被设置为「*」。

    2、因为我的springboot版本较新,所以网上通用的很多跨域配置对我不太适用。比如 Access-Control-Allow-Headers 不能直接设置为 *,而需要将特定的请求头给明确列出来才可生效。

    这次折腾了这么久,尝试了网上各种方法都不生效,主要就是因为以上两点,好在最后总算顺利解决了。

    作者:blayn
    出处:https://www.cnblogs.com/blayn/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    使用vue-cli搭建SPA项目
    NodeJS的环境搭建+传统ELmentui+vue开发
    vue路由
    Vue基础语法(样式绑定,事件处理,表单,Vue组件)
    动态规划 | 保留重复元素的LCS 1045
    动态规划 | 1007 最大连续子序列和
    数学问题 | 质因数分解:1096
    数学问题 | 连续质因数分解:1096
    数据结构 | 哈希表二次探查法 : 1078
    数学问题 | 1015 进制转换与素数问题
  • 原文地址:https://www.cnblogs.com/blayn/p/15564517.html
Copyright © 2011-2022 走看看