vue项目中使用proxy解决调试时的跨域问题,使用nginx解决前后端分离部署时的跨域问题

958 阅读4分钟

前言

我们在做项目的时候,经常碰到跨域问题,在Java中我们可以让后端使用CorsFilter这个类,给我们做相应的配置,允许哪些域名进行跨域请求,例如我之前就是这么做的,代码如下:

package com.jserm.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    public CorsConfig() {

    }

    @Bean
    public CorsFilter corsFilter() {
        // 1. 添加cors配置信息
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:3000");
        // config.addAllowedOrigin("http://localhost:2000");
        // config.addAllowedOrigin("*");
        // 设置是否发送cookie信息
        config.setAllowCredentials(true);
        // 设置允许请求的方式
        config.addAllowedMethod("*");
        // 设置允许的header
        config.addAllowedHeader("*");
        // 2.为url添加映射路径
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(corsConfigurationSource);
    }
}

但是如果后端不想写的话,,那就要靠我们自己了,在vue中我们可以使用webpack的devserver中的proxy解决在开发时候产生的问题,部署到线上的话,我们可以使用nginx的反向代理配置proxy_pass解决跨域问题,不过首先需要明确的有两点,1.在vue中使用proxy解决了开发时的跨域,但部署到线上是不生效的,所以部署到线上还得用到nginx,2.不能同时后端给你设置CorsFilter,你前端又去配置proxy,这样也会出问题,我自己的话就是配置好proxy之后,总是报404,一开始我总以为是我自己没有配置好,后面我在Java中把bean去掉就不报错了,接下来就开始进入正题了。

先说怎么使用proxy解决开发时的前端跨域问题

这里首先也得先明确一点,如果你想使用proxy解决开发时候跨域问题,封装axios的baseurl千万不要写成一个完整的url,不然它就会使用axios配置的baseurl拼接uri去发送请求,这样代理proxy就不会生效,例如你想从localhost:2000请求localhost:8088的接口,你如果把axios的baseurl写成了localhost:8088,那proxy就不会生效。正确的做法是你baseurl要写成"",或者你想要的前缀,例如"/api",这样它就会使用vue启动服务的地址+这个前缀+axios里面uri去请求,这个时候proxy就派上用场了,但是这里又有比较重要的一点,大概分为这两种情况,1.后端的接口统一加了/xxxx这个context-path前缀,2.后端的接口没有统一的context-path,比如localhost:8088/api/user/login,localhost:8088/api/user/register和localhost:8088/user/login,localhost:8088/user/register两种情况,我这里就举一个例子,其实关键还是在于理解
例如,我的baseUrl有前缀为"/api",我的proxy配置如下

devServer: {
  proxy: {
    '/api': {
      target: 'http://localhost:8088/',
      changeOrigin: true,
      pathRewrite: {
        "^/api": ""
      }
    }
  },
  port: 2000
}

这里表示的就是我axios请求http://localhost:2000/api/user/login会被proxy到http://locahost:8088/user/login我这里进行了pathRewrite重写是因为我后端的接口并没有统一加context-path,如果后端的接口都是localhost:8088/api/user/login,localhost:8088/api/user/register这种有统一前缀的,那么就不要进行pathRewrite重写了。
当然我这种情况baseUrl也可以写为"",然后proxy改为如下配置,但是非hash模式下这样修改也有注意的点,就是你baseUrl如果写的是一个空,那么axios的url千万千万要记住得加/前缀,不然它最后请求的url地址是localhost:2000/aticle/user/login而不是localhost:2000/user/login,我这里推荐axios的baseUrl写"/",这样你使用axios的方式的时候,url可加可不加/,非hash模式下千万不要使用'./',如果是这样,url总是会拼接上前端路由的路径

export const loginTest = ({ userEmail, password }) => {
  const data = {
    userEmail,
    password
  }
  return axios.request({
    url: '/user/login', //如果axios的baseurl是空,这里千万就补齐/,不然会拼接上的vue前端路由的路径
    data,
    method: 'post'
  })
}
devServer: {
  proxy: {
    '/': {
      target: 'http://localhost:8088/',
      // pathRewrite: {
      //   "^/api": ""
      // }
    }
  },
  port: 2000
}

使用nginx解决线上部署时的跨域问题

我还是以为自己为例,因为我自己的axios的baseUrl是写的"/api",所有的请求都会是这种格式localhost:2000/api/user/loigin, localhost:2000/api/user/register, localhost:2000/api/xxxxx,但是呢,我的后台接口并没有加统一的context-path api这个前缀,所以我的nginx的反向代理的配置如下

server {
    listen 80;
    server_name localhost;
    location =/ {
        root D:\blog-admin\dist;
        index index.html;
    }

    location ~* .*.(png|html|js|css|jpg)$ {
        root D:\blog-admin\dist;
    }

    location ^~ /index.html {
        root D:\blog-admin\dist;
    }
    location /api {
        proxy_pass http://127.0.0.1:8088/; 这里表示所有的localhost/api/xxx都会被代理为http://127.0.0.1:8088/xxxx,这里又会涉及nginx的proxy_pass路径的唯一拼接规则,具体就不在此展开
    }
}

总是

希望这篇文章能够帮到大家,并且一些不必要的踩坑,关键还是在于理解,另外千万不要把devServer的配置和nginx联系其他,他们之间没有任何的关系,可以理解为一个为前端调式的时候解决跨域问题的方法,一个为后端部署解决跨域的方法,重申一遍,两者之间没有任何关系,这样你在配置的时候就可以游刃有余了