问题
因为是第一次尝试前后端分离项目,之前完成了前端中包括登录、注册以及项目需要的一些核心功能。但是项目缺人所以又开始搞后端,准备先连接登录功能。前后端交互无非就是前端向后端发请求,同时携带特定的参数,而后端则根据前端的请求路径以及参数返回相应的数据,但这是理论上的,实际操作的时候,被如何正确使用Axios向后端某个路由发数据困扰许久。
前后端跨域
跨域分为三种:
端口跨域:源地址http:127.0.0.1:8848 目的地址 http://127.0.0.1:8080
域名跨域:源地址http:127.0.0.1:8848 目的地址 http://22.33.55.66:8080
协议跨域:源地址http:127.0.0.1:8848 目的地址 https://22.33.55.66:8080
正确实现
在前端配置Axios的baseURL为"/api",然后为它设置一个代理"http://localhost:8080"(后端地址)
# 开发环境接口地址
VITE_API_URL = /api
# 开发环境跨域代理,支持配置多个
VITE_PROXY = [["/api","http://localhost:8080"]]
在后端设置user的Controller的路由为"auth",设置login功能的路由为"login"
@RestController
@RequestMapping("auth")
@Tag(name = "auth", description = "认证相关的Controller")
public class AuthController {
private final AuthService authService;
@Autowired
public AuthController(AuthService authService) {
this.authService = authService;
}
@Operation(
method = "POST",
description = "用户登录",
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
content = @Content(mediaType = "application/json")
),
security = @SecurityRequirement(name = "", scopes = ""),
summary = "用户登陆"
)
@PostMapping("login")
public ResponseEntity<LoginVO> login(@RequestBody LoginParams login) {
ResponseEntity<LoginVO> entity;
System.out.println("");
try {
String token = authService.auth(login.getUsername(), login.getPassword());
entity = ResponseWrapper.responseEntityAccept(new LoginVO(token));
} catch (UserLoginErrorException e) {
entity = ResponseWrapper.responseEntityFail(e.getMsg());
}
return entity;
}
}
配置axios的url为"auth/login"(这个url,刚才设置的是baseURL),PROT1为auth
/**
* @name 登录模块
*/
// 用户登录
export const loginApi = (params: Login.ReqLoginForm) => {
return http.post<Login.ResLogin>(PORT1 + `/login`, params, { loading: false }); // 正常 post json 请求 ==> application/json
};
问题
设置Axios的baseURL为http://localhost:8080
这种方式成功地实现了登录功能,但是当我想要退出登录的时候发现一直出现跨域问题,因为源地址为http://localhost:8848而目标地址为http://localhost:8080出现了端口跨域,所以不进行跨域配置便无法成功响应。(bug修复了,复原不回去了,就不贴图了)
设置Axios的baseURL为/auth
此时通过查阅资料似乎已经理解到了代理的用处,于是想设置baseURL为auth,然后让所有带有auth的目的地址都代理到http://localhost:8080,这种方式仍然不奏效,虽然已经能够请求到后端的接口了,但是请求的路由错了,因为还是没有理解到使用vite.config.ts创建代理的时候下面这段代码的含义。
ewrite: path => path.replace(new RegExp(`^${prefix}`), ""),
正确思路
前端项目使用vite进行搭建,在vite.config.ts中有一个字段server是专门用于配置服务器的,我们可以使用该配置来解决跨域问题。请看下面的代码
/**
* 创建代理,用于解析 .env.development 代理配置
* @param list
*/
export function createProxy(list: ProxyList = []) {
const ret: ProxyTargetList = {};
for (const [prefix, target] of list) {
const httpsRE = /^https:\/\//;
const isHttps = httpsRE.test(target);
// https://github.com/http-party/node-http-proxy#options
ret[prefix] = {
target: target,
changeOrigin: true,
ws: true,
rewrite: path => path.replace(new RegExp(`^${prefix}`), ""),
// https is require secure=false
...(isHttps ? { secure: false } : {})
};
}
return ret;
}
在这段代码中,接收一个代理列表而后循环处理每个代理,使用prefix与tartget分别取出代理配置中的源地址与代理地址,而后重新封装成键值形式,其中最为关键的是rewrite:XX,这段代码的意思,是将最终请求地址中的源地址去掉,比如配置的时候源地址为/api,代理地址为http://localhost:8080,那么如果不将/api去掉,在最终的请求地址中就会多一个/api,就无法正确地发送请求。