本篇博客会介绍前后端分离项目如何实现跨域请求。
CORS(Cross-Origin Resource Sharing)问题的出现主要是因为浏览器的同源策略,同源的要求是:同协议,同IP,同端口。即不能在非同源情况下进行请求,实际上是为了保护用户的安全。
首先,准备一下frontend和backend的代码。这里为了创造非同源条件,前端跑在本机的8080端口下,后端跑在本机的8000端口下。
{
"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
<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>Documenttitle>
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>
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
的原理其实是标签不受同源策略的限制,即
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>
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";
}
我们对请求进行规定,以/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
才能停止项目,不然下次启动时会提示端口占用。