V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
madworks
V2EX  ›  Java

vue 前端 springboot 后端分离跨域求解

  •  
  •   madworks · 2020-10-27 14:51:27 +08:00 · 3661 次点击
    这是一个创建于 1270 天前的主题,其中的信息可能已经有所发展或是发生改变。
    上一周整合 springsecurity 写个项目,前端用 vue,302 跳转登录遇到跨域问题,一直无法解决,前后端都使劲浑身节数不得姐,不管用 @crossorigin,corsconfigaddorigin*、192168,前端设置 axiosCredentials,webpackproxy 都不行,求问怎么解决,还有问下大家是习惯 vue 前端打包后当成静态和后端放在一起运行,还是分开运行
    41 条回复    2020-10-27 22:41:05 +08:00
    jiangnan01
        1
    jiangnan01  
       2020-10-27 14:59:17 +08:00
    接口用 postman 能通吗?如果能通,前端在开发环境配 proxy 应该也是可以的,不需要后端做任何事
    至于到底是分开运行还是放到一起,看项目怎么要求了,能分开更好
    madworks
        2
    madworks  
    OP
       2020-10-27 15:01:26 +08:00
    @jiangnan01 没有 postman,就是本地能用,用同事机器访问我 ip 项目不能
    jiangnan01
        3
    jiangnan01  
       2020-10-27 15:04:31 +08:00
    @madworks 你自己运行起来是前后端分开的还是放在一起的?同事访问的方式呢?
    madworks
        4
    madworks  
    OP
       2020-10-27 15:08:06 +08:00
    @jiangnan01 我自己访问是分开的,同事是访问我项目前端。而且我们另一个 vue 开发的项目发现 webpack 代理那里不能用 ip,必须写域名
    OldActorsSmile
        5
    OldActorsSmile  
       2020-10-27 15:09:17 +08:00
    服务端 header 里配置允许跨域就好了,你看高德的 api,跨域调用它都没问题
    OldActorsSmile
        6
    OldActorsSmile  
       2020-10-27 15:10:15 +08:00
    JAVA 我不熟,php 是这样写的:
    header('Access-Control-Allow-Origin:*'); // *代表允许任何网址请求
    hafuhafu
        7
    hafuhafu  
       2020-10-27 15:12:17 +08:00
    盲猜可能是复杂请求没处理 OPTIONS 吧,跨域是浏览器的行为,如果接口本身是正常的,postman 不会管跨不跨域,肯定能通的。
    ljpCN
        8
    ljpCN  
       2020-10-27 15:12:40 +08:00 via Android
    建议贴上完整的前端域名和 http 请求信息
    madworks
        9
    madworks  
    OP
       2020-10-27 15:13:58 +08:00
    @OldActorsSmile 这个我写过,不行好像
    anonydmer
        10
    anonydmer  
       2020-10-27 15:14:14 +08:00
    搞不定就搞个 nginx 代理下,去掉跨域啦
    madworks
        11
    madworks  
    OP
       2020-10-27 15:15:25 +08:00
    @ljpCN 这个 springsecurity 代码里看到过,应该他内部已经做处理了
    jiangnan01
        12
    jiangnan01  
       2020-10-27 15:22:31 +08:00
    @madworks 你自己的前端项目配 proxy 了吗?
    madworks
        13
    madworks  
    OP
       2020-10-27 15:23:01 +08:00
    @jiangnan01 配了的
    OldActorsSmile
        14
    OldActorsSmile  
       2020-10-27 15:26:22 +08:00
    @madworks

    跨域的原理是浏览器为了安全而阻止。如果浏览器发现服务器 header 告诉它允许就可以。高德的 api 跨域就是这个原理。
    有图有真相,你试试: https://shoujihao.zhishifufei.cn/

    THESDZ
        15
    THESDZ  
       2020-10-27 15:54:29 +08:00
    1.本地调试,使用 proxyTable
    2.生产部署使用 nginx 反向代理到服务器 ip:port

    以上为本人解决方式,仅供参考
    NULL2020
        16
    NULL2020  
       2020-10-27 16:03:49 +08:00
    ```

    @Override
    public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
    .allowedOrigins("*")
    .allowCredentials(true)
    .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
    .allowedHeaders("*");
    }


    ```
    KuroNekoFan
        17
    KuroNekoFan  
       2020-10-27 16:05:28 +08:00
    没啥必要就置同域吧
    madworks
        18
    madworks  
    OP
       2020-10-27 16:21:41 +08:00
    @NULL2020 这样写过,没用
    madworks
        19
    madworks  
    OP
       2020-10-27 16:22:25 +08:00
    @THESDZ 加了一层,这样做的目的是什么
    THESDZ
        20
    THESDZ  
       2020-10-27 16:28:23 +08:00
    @madworks 对于用户来说,前后端的资源请求在同一域内
    whatCanIDoForYou
        21
    whatCanIDoForYou  
       2020-10-27 16:39:25 +08:00
    三种解决办法:
    1,nginx 配置映射 (我没有实操过。。)
    2,前端处理(我是后端)
    3,后端处理
    搞一个 配置类 或者配置文件(我是类)具体代码如下:
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Bean
    public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration corsConfiguration = new CorsConfiguration();
    /*是否允许请求带有验证信息*/
    corsConfiguration.setAllowCredentials(true);
    /*允许访问的客户端域名*/
    corsConfiguration.addAllowedOrigin("*");
    /*允许服务端访问的客户端请求头*/
    corsConfiguration.addAllowedHeader("*");
    /*允许访问的方法名,GET POST 等*/
    corsConfiguration.addAllowedMethod("*");
    urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
    return new CorsFilter(urlBasedCorsConfigurationSource);
    }
    }
    wellsc
        22
    wellsc  
       2020-10-27 16:43:08 +08:00
    配个反向代理?
    yaphets666
        23
    yaphets666  
       2020-10-27 16:44:22 +08:00
    nginx 呀我的哥 webpack proxy 这就离谱了啊 这是前端自己启动 webpack-dev-server 开发的时候用的 执行 build 命令打包后的前端工程跟 webpack proxy 没关系了
    Sapp
        24
    Sapp  
       2020-10-27 16:45:07 +08:00   ❤️ 1
    1. 试试 postman 这种可能不能跑通,没有下载就写个 node 调用一下看能不能通,能跑通就不是接口本身有问题
    2. 观察一下看看是不是 get 可以,post 不行,可能是复杂请求没有处理 option 的问题,如果都不行就不是这个问题
    3. 服务器设置一下允许跨域看看行不行,按理说这个是终极解决方案
    4. 如果服务器设置了跨域还是不行,那就继续检查一下 2 看看是不是没处理 option,理论上来讲,到这个阶段怎么都调用通了
    Sapp
        25
    Sapp  
       2020-10-27 16:47:22 +08:00
    另外前端和后端是不是同域我觉得根本无所谓,现在跨域根本就不是个事,全看你们公司的架构怎么设计的前后端部署这一块。
    vision1900
        26
    vision1900  
       2020-10-27 16:49:01 +08:00
    前端用 Proxy
    或者后端用个跨域中间件,没必要自己写,规则没有那么简单
    Express 这个中间件是 cors,一行代码解决战斗
    lzhlzhlc123
        27
    lzhlzhlc123  
       2020-10-27 16:50:58 +08:00
    前端打包成静态之后可以使用 nginx 做静态资源代理代理
    可以在 nginx.conf 文件中下面添加 server 模块 ->server 模块中添加需要监听的端口号->server 中添加 location 模块中使用 root 和 index 做静态代理 location 中使用 proxy_set_header 做代理

    server {
    listen 85;
    location / {
    root /usr/local/app/hr/dist;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
    }

    location /api {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://localhost:8091/sxwendu;
    }
    }
    cco
        28
    cco  
       2020-10-27 16:51:22 +08:00
    @CrossOrigin 注解- -。
    lzhlzhlc123
        29
    lzhlzhlc123  
       2020-10-27 16:52:02 +08:00
    实在不行配合一下楼上兄弟的后端代码,基本可以解决大部分问题了
    clf
        30
    clf  
       2020-10-27 16:54:37 +08:00
    前端代理就行,百度 Vue-cli 代理一大堆文章教程,或者弄个 nginx 搞反向代理 /api/ 到后端的端口路径。

    还有一种方法是前端代码 build 到后端的目录里,用 SpringBoot 作为静态文件服务器。
    ClutchBear
        31
    ClutchBear  
       2020-10-27 17:17:16 +08:00
    spring security 好像是有自己的跨域解决方式:
    我是这样处理的
    在 SecurityConfig 中添加这个 bean
    ```
    /**
    * 跨域
    * https://lolico.me/2020/04/26/Spring-Security-CORS/
    * https://blog.csdn.net/Keith003/article/details/104221174
    *
    * @return
    */
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.addAllowedOrigin("*"); // 根据实际的需要去设置
    configuration.addAllowedMethod("*"); // 同上
    configuration.addAllowedHeader("*");
    configuration.setMaxAge(3600L);
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
    }
    ```

    然后在重写的 configure 方法中, 添加
    ```
    // 禁用 CSRF
    http.csrf().disable();
    // 禁用表单登录
    http.formLogin().disable();
    // 防止 iframe 造成跨域
    http.headers().frameOptions().disable();
    // 开启跨域
    http.cors();
    ```

    在实现 AuthenticationFailureHandler 接口的 handler 中添加
    ```
    // 跨域 options 请求直接返回
    if (Objects.equals(request.getMethod(), HttpMethod.OPTIONS.toString())) {
    return;
    }
    ```
    yushxzh832
        32
    yushxzh832  
       2020-10-27 17:24:24 +08:00
    同楼上,可以看下是不是请求的 OPTIONS 被验证拦截了
    hb0730
        33
    hb0730  
       2020-10-27 17:26:51 +08:00
    /**
    * 创建跨域 filter
    *
    * @return {@link CorsFilter}
    */
    @Bean
    public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource corsConfiguration = new UrlBasedCorsConfigurationSource();
    corsConfiguration.registerCorsConfiguration("/**", build());
    return new CorsFilter(corsConfiguration);
    }

    private CorsConfiguration build() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowCredentials(true);
    configuration.addAllowedOrigin("*");
    configuration.addAllowedHeader("*");
    configuration.addAllowedMethod("*");
    configuration.addExposedHeader("content-disposition");
    configuration.setMaxAge(3600L);
    return configuration;
    }
    madworks
        34
    madworks  
    OP
       2020-10-27 18:18:34 +08:00
    @lzhlzhlc123 已收藏,不过暂时不想引入 nginx
    youla
        35
    youla  
       2020-10-27 18:25:17 +08:00
    如果是携带 cookies 跨域,应该不能这样写 Access-Control-Allow-Origin:*,要指定域名,如果有端口也要指定。

    如果不携带 cookies 跨域,axiosCredentials 设置为 false 就行了。
    jaylee4869
        36
    jaylee4869  
       2020-10-27 19:15:04 +08:00
    kekxv
        37
    kekxv  
       2020-10-27 19:19:38 +08:00 via iPhone
    有没有可能你请求的地址是 127.0.0.1
    Yourshell
        38
    Yourshell  
       2020-10-27 19:24:42 +08:00
    框架配置好后,你先单独请求看看响应带不带跨域头啊,没有不就证明框架配置有问题么。
    EminemW
        39
    EminemW  
       2020-10-27 22:22:06 +08:00
    首先跨域这玩意最好在 nginx 中配,不要侵入代码。。其次跨域头如果重复配,也会导致无法跨域,正常来说加这个 @crossorigin 注解就可以跨域的
    supuwoerc
        40
    supuwoerc  
       2020-10-27 22:39:57 +08:00
    webpack proxy 打完包就没有用了,这玩意是开发的时候用的。

    一般都是塞到后端程序的项目里面,如果要分开的话一般都是 Nginx 代理。
    supuwoerc
        41
    supuwoerc  
       2020-10-27 22:41:05 +08:00
    另外 postman 能通也没用。postman 又不是浏览器环境。

    跨域是浏览器的安全策略。postman 不存在这个策略。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2991 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 11:07 · PVG 19:07 · LAX 04:07 · JFK 07:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.