背景

对于前后端分离项目,前端和后端端口不能重复,否则会导致前端或者后端服务起不来。例如前端访问地址为: http://localhost:8080/ ,后端访问地址为 http://localhost:8081/ 。后端写好Controller,当用Axios访问该接口时,将会报错:

Access to XMLHttpRequest at ' http://localhost:8081/login ' from origin ' http://localhost:8080 ' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

本文内容从axios部署开始到解决跨域问题。

前端: Vue3;Axios 1.6.0 ;Element-Plus

后端:Springboot 2.7.14

这里提供两种解决方案,都是基于后端跨域访问的配置,前端不作任何允许跨域访问的设置,因为试过无效。

一、部署Axios

Axios的基本介绍:

(1)axios 是一个基于promise的HTTP库,支持promise所有的API

(2)浏览器端/node端(服务器端)都可以使用,浏览器中创建XMLHttpRequests

(3)支持请求/响应拦截器

(4)它可以转换请求数据和响应数据,并对响应回来的内容自动转换成 JSON类型的数据

(5)批量发送多个请求

(6)安全性更高,客户端支持防御XSRF

1. npm 安装 axios

npm install axios

2. 创建 request.ts,创建axios实例

在项目根目录下,也就是src目录下创建文件夹api/,并创建request.js ,该js用于创建axios实例。

import axios from 'axios';

import { ElMessage } from 'element-plus';

import { v4 as uuidv4 } from "uuid";

//ts使用

import { Md5 } from "ts-md5";

// 创建axios实例

const $http = axios.create({

// 请求的域名,基本地址,proxy 代理时会将“/api”以及前置字符串会被替换为真正域名

baseURL: '/api',

// 跨域请求时发送Cookie

withCredentials: true, // 视情况而定

// 超时时间

timeout: 5000,

headers: {

// 设置后端需要的传参类型

'content-type': 'application/json; charset=utf-8',

// "Lux-mateApiNonce": uuid, //每次调取接口生成的uuid

// "Lux-mateApiSignature": mateApi, //md5(method+requestURI+nonce+timestamp+appId+appSecret)

// "Lux-mateApiTimestamp": timestamp, // 每次调取接口的时间戳(秒级)

},

});

// 请求拦截器

$http.interceptors.request.use((config) => {

// 获取当前时间戳

const timestamp = parseInt(Date.now() / 1000);

const uuid = uuidv4(); // 生成UUID

console.log(parseInt(Date.now() / 1000),'3333333')

// console.log(config.method)

let signStr =config.method + config.url + uuid + timestamp + "Herdsric" + "Herdsric2024"

console.log('验签',signStr)

let mateApi = Md5.hashStr(signStr.toUpperCase());

console.log(mateApi)

config.headers['Lux-mateApiSignature'] = mateApi

config.headers['Lux-mateApiNonce'] = uuid //每次调取接口生成的uuid

config.headers['Lux-mateApiTimestamp'] = timestamp// 每次调取接口的时间戳(秒级)

config.headers = config.headers || {};

// if (localStorage.getItem("token")) {

// config.headers.token = localStorage.getItem("token") || "";

// }

return config;

});

// 响应拦截器

$http.interceptors.response.use((response) => {

return response;

}, (error) => {

ResponseProcessing(error);

});

/**

* 响应处理

* @param error

* @returns

*/

const ResponseProcessing = (error: { response: { state: any; data: any; }; }) => {

if (error.response) {

switch (error.response.state) {

case 401:

ElMessage.warning("资源没有访问权限!");

break;

case 404:

ElMessage.warning("接口不存在,请检查接口地址是否正确!");

break;

case 500:

ElMessage.warning("内部服务器错误,请联系系统管理员!");

break;

default:

return Promise.reject(error.response.data); // 返回接口返回的错误信息

}

} else {

ElMessage.error("遇到跨域错误,请设置代理或者修改后端允许跨域访问!");

}

};

export default $http;

在这里,我们自定义axois实例化对象,配置了默认的访问i后端ip和端口等,并在末尾使用export 导出api配置,便于在其他单文件中引入 request.ts.

3. 在main.ts中全局注册axios

import { createApp } from 'vue'

import './style.css'

import App from './App.vue'

import router from './router'

import ElementPlus from 'element-plus'

import 'element-plus/dist/index.css'

const app = createApp(App)

app.use(ElementPlus)

app.use(router)

app.mount('#app')

// createApp(App).use(router).mount('#app')

4. 创建api.ts文件夹

import $http from './Interceptor';

export function getTestData(params: any) {

return $http({

url: '/',

method: 'get',

params

})

}

4. 在页面中使用axios

import { getTestData } from "../http/API";

const fetchUserData = async () => {

try {

let params = {

};

const response = await getTestData(params);

if (response.data.code == 0) {

} else {

}

} catch (error) {

ElMessage.error("网络异常,请稍后再试");

console.error("There was an error fetching the data:", error);

}

};

4. 解决跨域问题。vite.config.ts

import { defineConfig } from 'vite'

import vue from '@vitejs/plugin-vue'

// import path from 'path';

// https://vitejs.dev/config/

export default defineConfig({

plugins: [vue()],

// 解决跨域问题

server: {

host: '0.0.0.0',

// port: 4000,

proxy: {

'/api': {

target: 'http://192.168.31.17:4000',

// secure: false, // 请求是否为https

changeOrigin: true,

rewrite:(path)=>path.replace(/^\/api/,'') //api替换为'',

},

},

},

// resolve: {

// alias: {

// '@': path.resolve(__dirname, 'src'),

// },

// },

css: {

preprocessorOptions: {

less: {

additionalData: `@import "@/assets/style/base.less";`,

}

},

},

})