当下,最流行的就是前后分离
项目,也就是前端项目
和后端接口
并不在一个域名之下,那么前端项目访问后端接口必然存在跨域
的行为.
解决开发环境的跨域问题
开发环境的跨域
开发环境的跨域,也就是在vue-cli脚手架环境
下开发启动服务时,我们访问接口所遇到的跨域问题,vue-cli为我们在本地开启了一个服务
,可以通过这个服务帮我们代理请求
,解决跨域问题
这就是vue-cli配置webpack的反向代理
vue-cli的配置文件即vue.config.js
,这里有我们需要的 代理选项
module.exports = {
devServer: {
// 代理配置
proxy: {
// 这里的api 表示如果我们的请求地址有/api的时候,就出触发代理机制
// localhost:8888/api/abc => 代理给另一个服务器
// 本地的前端 =》 本地的后端 =》 代理我们向另一个服务器发请求 (行得通)
// 本地的前端 =》 另外一个服务器发请求 (跨域 行不通)
'/api': {
target: 'www.baidu.com', // 我们要代理的地址
changeOrigin: true, // 是否跨域 需要设置此值为true 才可以让本地服务代理我们发出请求
// 路径重写
pathRewrite: {
// 重新路由 localhost:8888/api/login => www.baidu.com/api/login
'^/api': '' // 假设我们想把 localhost:8888/api/login 变成www.baidu.com/login 就需要这么做
}
},
}
}
}
生产环境的跨域
生产环境表示我们已经开发完成项目,将项目部署到了服务器上,这时已经没有了vue-cli脚手架的辅助
了,我们只是把打包好的html+js+css
交付运维人员,放到Nginx
服务器而已,所以此时需要借助Nginx
的反向代理来进行
server{
# 监听9099端口
listen 9099;
# 本地的域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://baidu.com
location ^~ /api {
proxy_pass http://baidu.com;
}
}
export function login(data) {
// 返回一个axios对象 => promise // 返回了一个promise对象
return request({
url: '/sys/login', // 因为所有的接口都要跨域 表示所有的接口要带 /api
method: 'post',
data
})
}
在传统模式中,我们登录的逻辑很简单,如图
上图中,组件直接和接口打交道,这并没有什么问题,但是对于用户token这一高频使用的
钥匙
,我们需要让vuex来介入,将用户的token状态共享,更方便的读取,如图
实现store/modules/user.js基本配置
// 状态
const state = {}
// 修改状态
const mutations = {}
// 执行异步
const actions = {}
export default {
namespaced: true,
state,
mutations,
actions
}
设置token的共享状态
const state = {
token: null
}
在utils/auth.js
中,基础模板已经为我们提供了获取token
,设置token
,删除token
的方法,可以直接使用
只需要将存储的key放置成特定值即可
import Cookies from 'js-cookie'
const TokenKey = 'hrsaas-ihrm-token' // 设定一个独一无二的key
export function getToken() {
return Cookies.get(TokenKey)
}export function setToken(token) {
return Cookies.set(TokenKey, token)
}export function removeToken() {
return Cookies.remove(TokenKey)
}
初始化token状态 - store/modules/user.js
import { getToken, setToken, removeToken } from '@/utils/auth'
// 状态
// 初始化的时候从缓存中读取状态 并赋值到初始化的状态上
// Vuex的持久化 如何实现 ? Vuex和前端缓存相结合
const state = {
token: getToken() // 设置token初始状态 token持久化 => 放到缓存中
}
提供修改token的mutations
// 修改状态
const mutations = {
// 设置token
setToken(state, token) {
state.token = token // 设置token 只是修改state的数据 123 =》 1234
// vuex变化 => 缓存数据
setToken(token) // vuex和 缓存数据的同步
},
// 删除缓存
removeToken(state) {
state.token = null // 删除vuex的token
removeToken() // 先清除 vuex 再清除缓存 vuex和 缓存数据的同步
}
}
// 执行异步
const actions = {
// 定义login action 也需要参数 调用action时 传递过来的参数
async login(context, data) {
const result = await login(data) // 实际上就是一个promise result就是执行的结果
// axios默认给数据加了一层data
if (result.data.success) {
// 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的
// 现在有用户token
// actions 修改state 必须通过mutations
context.commit('setToken', result.data.data)
}
}
}
在Vuex中如何来管理共享状态
// 响应拦截器
service.interceptors.response.use(response => {
// axios默认加了一层data
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务已经错误了 还能进then ? 不能 ! 应该进catch
Message.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
}, error => {
Message.error(error.message) // 提示错误信息
return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch
})