目录
跨域问题:
协议(http/https等)、域名(如www.baidu.com)、端口号(如8080)有一个不同都算跨域。
因为一个端口号只能跑一个程序,所以前后端分离代表着项目一定存在跨域问题。
前端在开发环境时需要解决跨域问题,但是在部署到服务器之后,就需要后端来解决。
开发环境下前端解决跨域:
在vue.config.js文件下,配置反向代理proxy
devServer: {
// host: 'localhost', // ip 本地
// open: true, // 配置自动启动浏览器
port: 3000, // 设置端口号
proxy: {
'/api': { // 接口以api开头的才用代理
target: '服务器ip', //axiso实例里的baseURL的值(后端路径)
changeOrigin: true,
pathRewrite: {
//这里理解成用‘/api’代替target里面的地址,组件中我们调接口时直接用/api代替
// 比如我要调用'http://xxx.xxx.x.xxx:8080/login',直接写‘/api/user/add’即可 代理后地址栏显示/
'^/api': '',
}
}
},
},
changeOrigin:true指是否改变域名:在本地会创建一个虚拟服务端,在这里发送并接收请求数据,这样数据交互就不会有跨域问题。实际上这个东西作用不大,感兴趣的话可以百度了解一下。https://blog.youkuaiyun.com/Old_Soldier/article/details/127204618
pathRewrite:路径重写,当实际需要请求的接口路径里没有api的时候,就需要用到路径重写(后端识别的时候把api替换成空)
最后我们调用的接口基础路径就是target+pathRewrite(使用实例参考axios的封装)
axios的封装:
axios让我们对接口的使用变得很简单,但在项目中,接口数量往往会一直增加,有一些操作,比如在请求头中夹带token,需要我们在每个接口前面都进行添加,会让代码非常冗余,且难以维护。
但如果我们对axios进行封装,那我们往往只需要写一次代码,并且后期管理或维护都能变得很简便。
引入axios:
在main.js引入,通过npm install axios -g安装
// axios; // npm install axios -g
import axios from "axios";
axios.defaults.withCredentials = true;
api路径的搭建:
在src文件下,创建api/_BaseAxios文件
import axios from "axios"; // 引入axios
import AxiosInterceptors from './_AxiosInterceptors' // 引入拦截器规则
import {
RBAC_BASE_URL, // api路径
TIMEOUT // 超时时长
} from '../const.js'
let requestConfig = {
baseURL: RBAC_BASE_URL, // 配置api路径
timeout: TIMEOUT // 配置超时时长
}
const baseAxios = axios.create(requestConfig); // 创建axios实例
AxiosInterceptors.setInterceptors(baseAxios); // 使用拦截器规则
export default baseAxios;
baseURL就是接口基础路径,所以这里也可以写成baseURL:'/api',因为开发环境和生产环境里写的baseURL不一样,所以在const.js里配置以下代码会更方便。
// export const PROJECT_NAME = 'Panda';
// export const TOKEY_ATTR_NAME = 'X-Access-Token'; // TOKEN的属性名(即客户端传token到服务端,token的属性名)
// export const IS_LOGIN_NEEDED = true; // 系统是否需要登录后使用
let rbacBaseUrl; // 基础API地址
switch (process.env.NODE_ENV) {
case "production": // 发布到服务器 npm run build
rbacBaseUrl = '服务器ip/';
break;
case "development": // 本机前端开发调试 npm run serve
default:
rbacBaseUrl = '/api';
break;
}
export const RBAC_BASE_URL = rbacBaseUrl;
export const TIMEOUT = 10000; // 一般请求超时时间
// export const UPLOAD_TIMEOUT = 0; // 指定文件上传请求超时的毫秒数(0 表示无超时时间)
// //文件地址
// export const uploadImgUrl = '服务器ip/';
process.env包含关于环境变量的信息。
process.env.NODE_ENV是一个用户自定义的变量,用来判断生产环境还是开发环境,一般生产环境就是production,开发环境就是development。https://blog.youkuaiyun.com/qq_31967569/article/details/116164721
配置拦截器:
最好在api路径下添加一个js文件(与_BaseAxios同级),我的命名是_AxiosInterceptors,拦截器包含request和response两部分,request用来管理接口发送请求前的处理,response处理接收后的数据。
import store from "@/store/index";
function setInterceptors(axios) {
// 在被then()和catch()方法处理之前,把 客户端请求 拦截下来优先处理
// api 返回的数据均为json,如果请求没有指明,则默认视为json
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
if (store.state.token) {
// 添加请求头
config.headers['token'] = store.state.token
config.headers['Authorization'] = store.state.token
}
return config;
}, error => {
// 对请求错误做些什么
return Promise.reject(error);
});
// 在被then()和catch()方法处理之前,把 服务器返回结果 拦截下来优先处理
axios.interceptors.response.use(response => {
/*** 响应成功拦截器 */
// console.log("response", response)
return response;
}, error => {
return Promise.reject(error);
});
return axios;
}
export default {
setInterceptors
}
调用接口实例:
添加接口文件,写接口的时候注意一下method类型是get、post还是put之类的,这个会影响参数传递的格式,data还是params。以下是常用的接口类型。
import BaseAxios from "../_BaseAxios";
import ResHelper from "../_ResponseHelper.js";
/**
* @description 登录 post,data
* @param {String} account 账号
* @param {String} password 密码
*/
function login(params) {
return BaseAxios({
url: `system/Login/login`,
method: "post",
data: {
"account": params.account,
"password": params.password,
}
// data: params,
})
// .then(ResHelper.handler);
}
/**
* @description 注册 post,params
* @param {Integer} account 账号
* @param {String} password 密码
* @param {String} code 验证码
* @param {String} mailbox 邮箱
* @param {String} username 名字
* @param {Integer} phoneNumber 电话号码
*/
function register(params) {
return BaseAxios({
url: `system/Login/register`,
method: "post",
params: params
})
}
/**
* @description 获取用户信息 get
* @param {String} Authorization 验证信息
*/
function getUser() {
return BaseAxios({
url: `system/Login/user`,
method: "get",
})
}
/**
* @description 获取申请列表 get,params
* @param {Integer} pageSize 页数
* @param {String} keyword 姓名
*/
function getApplyList(params) {
return BaseAxios({
url: `system/Personal/list`,
method: "get",
params: params,
})
}
export default {
login,
register,
getUser,
getApplyList,
}
import BaseAxios from "../_BaseAxios";
import ResHelper from "../_ResponseHelper.js";
/**
* @description 增加熊猫信息 post,data
* @param {int} number 熊猫编号
* @param {String} birth 出生日期
* @param {String} dna DNA
* @param {String} englishName 英文名
* @param {String} gender 性别
* @param {String} image 照片
* @param {String} name 名字
* @param {String} roostPosition 栖息地
*/
function addPanda(params) {
return BaseAxios({
url: `system/Panda/panda/add`,
method: "post",
data: params,
})
}
/**
* @description 修改熊猫信息 put,data
* @param {int} number 熊猫编号
* @param {String} birth 出生日期
* @param {String} dna DNA
* @param {String} englishName 英文名
* @param {String} gender 性别
* @param {String} image 照片
* @param {String} name 名字
* @param {String} roostPosition 栖息地
*/
function editPanda(params) {
return BaseAxios({
url: `system/Panda/panda/edit`,
method: "put",
data: params,
})
}
export default {
addPanda,
editPanda,
}
关于_ResponseHelper文件,本来是想通过他处理获取的数据的,但由于本次项目接口code情况不一致,就放弃使用了,如果要使用可以参考以下代码:
import SysError from "../sys/SysError.js"
// 一般处理方法
function handler(res) {
switch (res.data.code === 200) {
case true:
return res.data.result;
default:
throw new SysError(res.data.code, res.data.message, res.data.result);
}
}
export default {
handler
}
src/sys/SysError:
class SysError extends Error {
constructor(code, message, data) {
super(message);
this.code = code;
this.data = data;
}
}
module.exports = SysError;
最后在需要调用接口的页面引入接口文件,就可以调用了,然后就是按情况处理数据之类的,如果不知道传过来的数据是什么就log一下,看看接口返回的response是什么。
当然也可以不封装,不封装一样可以用。