上文 講到瀏覽器因為安全的思考,設定了同源策略。這就是跨域的形成原因,也談到了跨域的一些解決方案。
本文就上篇文章的實踐,在專案開發時好作為參考資料。
準備環境
在開始之前,先說說實驗環境:
前端採用 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"
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結