前言
上文讲到浏览器因为安全的思考,设置了同源策略。这就是跨域的形成原因,也谈到了跨域的一些解决方案。
本文就上篇文章的实践,在项目开发时好作为参考资料。
准备环境
在开始之前,先说说实验环境:
前端采用 Vue3 搭建,端口为 8080。
后端采用 Spring Boot 搭建,端口为 8888。
后端测试接口:
@RestController
public class HelloController {
@GetMapping("/hello")
public Map hello(){
HashMap result = new HashMap();
result.put("message", "Hello World!");
return result;
}
}
启动项目,测试一下:
curl localhost:8888/hello
{"message":"Hello World"}
解决前后端跨域可以说就是解决 AJAX 跨域。上文说到四种跨域方案,其中 CORS 和 代理服务器 为常见解决方案。
CORS
使用 @CrossOrigin 注解
@CrossOrigin
可以用在类或者方法上:
@CrossOrigin(origins = "http://localhost:8080")
@RestController
public class HelloController
写在类上,表示该类的所有方法对应的接口浏览器都不会拦截。
@GetMapping("/hello")
@CrossOrigin(origins = "http://localhost:8080")
public String hello()
写在方法上,表示该方法对应的接口浏览器不会拦截。
实现 WebMvcConfigurer
创建一个类 CorsConfig
,使用 @Configuration
标识它为配置类;实现 WebMvcConfigurer
,重写 addCorsMappings
方法:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080");
}
}
需要注意的是,如果设置 Access-Control-Allow-Origin
为 *
,Access-Control-Allow-Credentials
就不能设置为 true。
Filter
创建一个类 CorsFilter
,使用 @Configuration
标识它为配置类;实现 Filter
,实现 doFilter
方法:
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, response);
}
}
更多 CORS 头部信息,可以 参考文档。
测试
在前端代码中或者用浏览器打开前端监听的端口,输入以下 JavaScript 代码:
fetch('http://localhost:8888/hello')
.then(response => response.json())
.then(json => console.log(json))
返回:
{
"message": "Hello World"
}
代理服务器
nginx
在开发过程中,前端会自己起一个服务来调试代码。于是 nginx 可以监听 80 端口,分别反向代理前端服务和后台服务。
server {
listen 80;
server_name 127.0.0.1;
location / {
proxy_pass http://127.0.0.1:8080;
}
location /api/ {
proxy_pass http://127.0.0.1:8888/;
}
}
需要注意的是,后端反向代理端口后要加上符号 /。否则访问 127.0.0.1/api/hello 就会反向代理到 http://127.0.0.1:8888/api/hello 而不是 http://127.0.0.1:8888/hello。
前端写完代码之后,可以将代码打包成静态文件,使用 nginx 来解析。
server {
listen 80;
server_name 127.0.0.1;
index index.html;
root /home/kang/vue-demo/dist;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:8888/;
}
}
需要注意的是,如果前端使用 history 来模拟 url,那在代理的过程中需要重写跳转规则:try_files $uri $uri/ /index.html。该语句表示 URL 的跳转由 index.html 管理。删除导致前端项目路由失效且 nginx 响应 404。
测试
在前端项目中,或者用浏览器打开,输入下列代码:
fetch('/api/hello')
.then(response => response.json())
.then(json => console.log(json))
返回:
{
"message": "Hello World"
}
node
在根目录中打开 vue.config.js
(如果没有就新建)。写下如下语句:
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:8888",
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
这里需要注意的是,这里的 pathRewrite,也就是路径重写。将 /api 前缀会去掉了。这样访问 /api/hello 才是 http://127.0.0.1:8888/hello,而不是 http://127.0.0.1:8888/hello。
测试
在前端项目中,或者用浏览器打开,输入下列代码:
fetch('/api/hello')
.then(response => response.json())
.then(json => console.log(json))
返回:
{
"message": "Hello World"
}
必须 注册 为本站用户, 登录 后才可以发表评论!