本篇博客會介紹前後端分離項目如何實現跨域請求。
CORS(Cross-Origin Resource Sharing)問題的出現主要是因爲瀏覽器的同源策略,同源的要求是:同協議,同IP,同端口。即不能在非同源情況下進行請求,實際上是爲了保護用戶的安全。
首先,準備一下frontend和backend的代碼。這裏爲了創造非同源條件,前端跑在本機的8080端口下,後端跑在本機的8000端口下。
- 前端利用yarn創建的項目,webpack-dev-server作爲服務器。前端項目結構和主要代碼如下:
package.json
{
"name": "website",
"version": "1.0.0",
"main": "y",
"license": "MIT",
"scripts": {
"build": "webpack",
"start": "webpack-dev-server --port '8080'"
},
"dependencies": {
"axios": "^0.19.1",
"axios-jsonp-pro": "^1.1.7",
"css-loader": "^3.4.2",
"element-ui": "^2.13.0",
"file-loader": "^5.0.2",
"style-loader": "^1.1.3",
"ts-loader": "^6.2.1",
"typescript": "^3.7.5",
"vue": "^2.6.11",
"vue-loader": "^15.8.3",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}
webpack.config.js
const Vlp = require('vue-loader/lib/plugin');
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'main.js'
},
mode: 'development',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
{
test: /.(eot|woff|woff2|ttf)([\\\\\\\\?]?.*)$/,
loader: "file-loader"
}
]
},
plugins: [
new Vlp()
]
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="./dist/main.js"></script>
</body>
</html>
main.js
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import app from './pages/app.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(app)
});
pages/app.vue
<template>
<div>
</div>
</template>
<style scoped>
</style>
<script>
export default {
};
</script>
- 後端新建了一個springboot項目,只改動了入口文件和配置了端口。
SeckillApplication.java
package com.example.seckill;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
@SpringBootApplication
public class SeckillApplication {
@GetMapping("/test")
public String test() {
return "hello";
}
public static void main(String[] args) {
SpringApplication.run(SeckillApplication.class, args);
}
}
一、JSONP
jsonp
的原理其實是<script>
標籤不受同源策略的限制,即src
屬性的值可以和當前站點非同源。使用jsonp
可以通過jquery
來實現,也推薦大家使用axios-jsonp
或axios-jsonp-pro
,通過yarn add axios-jsonp
即可安裝,詳細用法可以訪問 yarn
官網。只需要改動pages/app.vue
即可。
<script>
import axios from 'axios-jsonp-pro';
export default {
created: function() {
axios
.jsonp("http://127.0.0.1:8000/api/test")
.then(result => {console.log(result)})
.catch(err => {console.log(err.message)});
}
};
</script>
請求成功,我們能看到我們需要的字符串hello
。
二、後端跨域規則
- 首先我們使用
axios
進行網絡請求,該組件沒有跨域功能。
<script>
import axios from "axios";
export default {
created: function() {
axios.get('http://127.0.0.1:8000/api/test')
.then(response=>{console.log(response)});
};
</script>
- 我們只需要在方法上添加註解
@CrossOrigin
,並設定允許進行跨域請求的地址,即可。
@GetMapping("/test")
@CrossOrigin(origins = {"http://127.0.0.1:8080", "http://localhost:8080"})
public String test() {
return "hello";
}
三、使用Nginx進行反向代理
我們對請求進行規定,以/api/
開頭的請求都交給後端服務器,以/
開頭的請求交給前端服務器,實現代理即可。下面是nginx配置文件,注意先後順序。
nginx.conf
server {
listen 127.0.0.1:80;
location /api/ {
proxy_pass http://127.0.0.1:8000;
}
location / {
proxy_pass http://127.0.0.1:8080;
}
}
重啓nginx服務後,我們需要對前端代碼進行改寫,後段代碼去掉@CrossOrigin
註解即可。
<script>
import axios from "axios";
export default {
created: function() {
axios.get('/api/test').then(response=>{console.log(response)});
}
};
</script>
我們直接通過Nginx服務器訪問http://127.0.0.1
即可。
四、請求時添加請求頭
這種方法較爲簡單,按照瀏覽器提示添加相應的請求頭即可,這裏不做演示。
五、總結
本次試驗中有大量的多餘代碼,請讀者自行忽略。另外,復現的時候有幾點需要注意:
- 前端項目每次都需要執行
yarn run build
先編譯,再yarn run start
啓動項目。 - 停止項目時需要先按
Ctrl + D
,再按Ctrl + C
才能停止項目,不然下次啓動時會提示端口占用。 - 需要即時清除瀏覽器緩存。