前端跨域解决方案
跨域是前端独有的 后端不存在这个概念
- 跨域是浏览器为了安全而做出的限制策略
- 浏览器请求必须遵循同源策略:同域名,同端口,同协议
跨域主要分为三种:
CORS跨域,JSONP跨域,代理跨域
CORS跨域
基本概念:
CORS跨域-服务端设置,前端直接调用
说明:后台允许前端某个站点访问
由后端来做设置,前端只管调用
前端给后端发送请求后可以观察请求头中的
Access-Control-Allow-Origin 表示支持哪些域名来访问我
Access-Control-Allow-Credentials 表示允许前端传递Cookie信息
JSONP跨域
基本概念:JSONP跨域-前端适配-后端配合
说明:前后台同时改造
安装JSONP:
执行cnpm install jsonp --save-dev 安装在生产环境下
然后使用jsonp发送请求
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ifBGiNse-1591666768601)(C:\Users\xzp\AppData\Roaming\Typora\typora-user-images\image-20200404155053430.png)]
JSONP不一样的是这个并不是XHR请求 是在JS中的
接下来先安装必备的插件:
npm install vue-lazyload element-ui node-sass sass-loader vue-awesome-swiper
vue-axios vue-cookie --save-dev
对项目进行路由封装:
在src目录下创建一个router.js文件做主控路由
下面的代码分别表示
/ 默认首页进入home页面
然后/index则进入index页面 index,product,detail属于home的子路由
import Vue from 'vue'
import Router from 'vue-router'
import Home from './pages/home'
import Index from './pages/index'
import Product from './pages/product'
import Detail from './pages/detail'
import Cart from './pages/cart'
import Order from './pages/order'
import OrderConfirm from './pages/orderConfirm'
import OrderList from './pages/orderList'
import OrderPay from './pages/orderPay'
import AliPay from './pages/alipay'
// 将路由注册到Vue中
Vue.use(Router)
// 导出路由
export default new Router({
routes:[
{
path:'/',
name:'home',
component:Home,
children:[
{
path:'/index',
name:'index',
component:Index
},
{
path:'/product/:id',
name:'product',
component:Product
},
{
path:'/detail/:id',
name:'/detail',
component:Detail
},
]
},
{
path:'/cart',
name:'/cart',
component:Cart
},
{
path:'/order',
name:'order',
component:Order,
children:[
{
path:'list',
name:'order-list',
component:OrderList,
},
{
path:'confirm',
name:'order-confirm',
component:OrderConfirm,
},
{
path:'pay',
name:'order-pay',
component:OrderPay,
},
{
path:'alipay',
name:'Alipay',
component:AliPay,
},
]
},
]
});
写完路由信息以后需要注册进Vue ,在main.js中注册进vue
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
现在再看看页面的设计home.vue:
<template>
<div>
home
<nav-header></nav-header>
<router-view></router-view>
<nav-footer></nav-footer>
</div>
</template>
<script>
import NavHeader from "./../components/NavHeader"
import NavFooter from "./../components/NavFooter"
export default {
name:'nav-home',
components:{
NavHeader,
NavFooter
}
}
</script>
其中是子路由的页面
而是在下面定义好的公共页面
子路由会直接引用父路由的页面,这样就可以做到页首和页尾通用了
Storage封装
Cookie,localStorage,sessionStorage三者的区别?
为什么要封装Storage,本身不是已经由API?
现在先回答第一个问题:
Cookie,localStorage,sessionStorage三者的区别:
-
存储大小:Cookie 4K,Storage 5M
-
有效期:Cookie拥有有效期,Storage永久存储
-
Cookie会发送到服务端,存储在内存中,Storage存储在浏览器端
-
路径:Cookie有路径限制,Storage只存储在域名下
-
API:Cookie没有特定的API,Storage有对应的API
在使用上如果我们要发送一个非常长的JSON大报文,那么就需要Storage的存储大小了
这个时候用Cookie就不太合适了
sessionStorage其实是在内存中存储的,永久存储的实际上是localStorage
为什么要封装Storage
-
Storage本身有API,但是只是简单的key/value形式
-
Storage只能存储字符串,需要人工转换成json对象
-
Storage只能一次性清空,不能单个清空
Sotrage封装代码:
/**
* Storage封装
*/
const STORAGE_KEY = 'mall'
export default{
// 存储值
setItem(key,value,module_name){
if(module_name){
let val = this.getItem(module_name);
val[key] = value;
this.setItem(module_name,val);
}else{
let val = this.getStorage();
val[key] = value;
window.sessionStorage.setItem(STORAGE_KEY,JSON.stringify(val));
}
},
// 获取某一个模块下面的的属性user下面的userName
getItem(key,module_name){
if(module_name){
let val = this.getItem(module_name);
if(val) return val[key];
}
this.getStorage()[key];
},
// 获取指定key下的所有value
getStorage(){
return JSON.parse(window.sessionStorage.getItem(STORAGE_KEY) || '{}');
},
// 清除Storage
clear(key,module_name){
let val = this.getStorage();
if(module_name){
delete val[module_name][key];
}else{
delete val[key];
}
window.sessionStorage.setItem(STORAGE_KEY,JSON.stringify(val));
}
}
接口错误拦截
- 统一报错
- 未登录统一报错
- 请求值,返回值统一处理
下面复习一下axios请求
可以查看网站https://www.npmjs.com/package/axios
// 根据前端的跨域方式做调整
axios.defaults.baseURL = '/api';
axios.defaults.timeout = 8000;
// 接口错误拦截(一般后端都是返回data,status,msg三个值)
axios.interceptors.response.use(function(response){
let res = response.data;
if(res.status == 0){
return res.data;
}else if(res.status == 10){
// 如果状态码为10代表没有登录
window.location.href = '/#/login';
}else{
alert(res.msg);
}
})
接口环境设置
- 开发上线的不同阶段,需要不同的配置
- 不同的跨域方式,配置不同
- 打包的时候统一注入环境参数,统一管理环境,输出不同的版本
解决方案:创建一个env.js
process.env:获取nodejs进程里边的环境变量
let baseURL;
switch (process.env.NODE_ENV) {
case 'dev':
baseURL = 'dev.itsnkkka.cn'
break;
case 'test':
baseURL = 'test.itsnkkka.cn'
break;
case 'prod':
baseURL = 'prod.itsnkkka.cn'
break;
default:
baseURL = 'www.itsnkkka.cn'
break;
}
export default{
baseURL
}
Mock设置
- 开发阶段,为了高效率,需要提前Mock
- 减少代码冗余,灵活插拔
- 减少沟通,减少接口联调时间
三种方案:
- 本地创建json文件
- easy-mock平台
- 集成Mock API