vue学习过程总结(07) - vue的后台服务API封装及跨域问题的解决
以登录流程为例说明接口的封装。
1.登录调用后台的登录api
登录界面的代码
<template> <div class="login-page"> <div class="login-container"> <div class="login-title">后台管理系统</div> <el-form ref="loginForm" :model="loginForm" :rules="rules" auto-complete="on" label-position="left" class="login-form" > <el-form-item prop="username"> <el-input prefix-icon="el-icon-s-custom" v-model="loginForm.username" placeholder="用户名" name="username" type="text" tabindex="1" auto-complete="off" /> </el-form-item> <el-form-item prop="password"> <el-input prefix-icon="el-icon-lock" type="password" v-model="loginForm.password" placeholder="密码" name="password" tabindex="2" auto-complete="off" @keyup.enter.native="submitForm()" /> </el-form-item> <div class="login-btn"> <el-button :loading="loading" type="primary" @click="submitForm()">登录</el-button> </div> <p class="login-tips">Tips : 一条小尾巴。。。</p> </el-form> </div> </div> </template> <script> import { vuetest } from '@/api/index' var validateUsername = (rule, value, callback) => { console.log(value); if (value == undefined || value === "") { callback(new Error("请输入用户名")); } else { callback(); } }; var validatePassword = (rule, value, callback) => { if (value == undefined || value === "") { callback(new Error("请输入密码")); } else { callback(); } }; export default { name: "Login", data() { return { loginForm: { username: "admin", password: "111111" }, rules: { username: [ { required: true, trigger: "blur", validator: validateUsername } ], password: [ { required: true, trigger: "blur", validator: validatePassword } ] }, loading: false }; }, methods: { submitForm() { this.$refs.loginForm.validate(valid => { if (valid) { this.loading = true; // 方法后台验证登录信息,验证成功后 vuetest().then(res => { console.log("===============vue test==========="); console.log(res); console.log(res.data.status); console.log(res.data.token); var tk = res.data.token; this.$store.dispatch("user/login", this.loginForm).then(() => { this.$store.dispatch("user/setTokenStore", tk); // 信息成功存储在vuex后跳转页面 this.$router.push("/home"); this.loading = false; }); // this.$router.push("/home"); // this.loading = false; }).catch(error => { console.log("===============vue test error==========="); console.log(error); }) // 将用户信息报存在vuex中 // this.$store.dispatch("user/login", this.loginForm).then(() => { // // 信息成功存储在vuex后跳转页面 // this.$router.push("/home"); // this.loading = false; // }); //this.$router.push("/home"); //localStorage.setItem('ms_username', this.loginForm.username); } else { this.$message.error("登录异常"); return false; } }); } } }; </script>
2.请求api的封装
import { vuetest } from '@/api/index' --- 引用src/api/idex.js文件中的export的vuetest 请求。src/api/idex.js中有请求方式、请求参数等设置
vuetest().then(res => { ----- res请求服务端接口返回的数据
src/api/idex.js文件代码
// api封装示例 // 导入配置好的axios文件 import Axios from "@/axios" // 封装axios请求函数,并用export导出 export function getItemList(datas) { return Axios({ url: "/api/getItemList", method: "post", headers: { 'Content-Type': 'application/x-www-form-urlencoded' //设置请求头请求格式form }, data: datas }) } export function getItem(datas) { return Axios({ url: "/api/getItem", method: "post", headers: { 'Content-Type': 'application/json' //设置请求头请求格式为json }, data: datas }) } export function getItemInfo(datas) { return Axios({ url: "/api/getItemInfo"+datas, method: "get", }) } export function vuetest(datas) { return Axios({ url: "/vue/test", method: "post", headers: { 'Content-Type': 'application/json' //设置请求头请求格式为json }, data: datas }) }
说明:
调用最后一个函数,专注于请求参数的处理。
return Axios({ ----- 是ajax请求的处理,Axios是import Axios from "@/axios"中导出的对象
3.ajax请求的进一步封装,主要是对所有ajax请求的一些共同的参数的设定,如超时时间、根路径
src/axios中的index文件(这个index.js文件的名字应该是不能改变的,所有导入的路径没有确定到文件而是目录)
//引入 axios库 import axios from 'axios' //引入 node中自带的qs模块(数据格式转换) import qs from 'qs' /* 2.全局默认配置 */ let baseURL // 判断开发环境(一般用于本地代理) // if (process.env.NODE_ENV === 'development') { // 开发环境 // baseURL = 'http://localhost:8082/VoucherWebService' // 你设置的本地代理请求(跨域代理),下文会详细介绍怎么进行跨域代理 // } else { // 编译环境 // if (process.env.type === 'test') { // 测试环境 // baseURL = 'http://sw.apitest.com' // } else { // 正式环境 // baseURL = 'http://sw.api.com' // } // } // 配置axios的属性 axios.defaults.timeout = 6000; // 请求超时时间1分钟 //axios.defaults.baseURL = baseURL; // 你的接口地址 axios.defaults.responseType = "json"; axios.defaults.withCredentials = false; //是否允许带cookie这些 /*你也可以创建一个实例,然后在实例中配置相关属性,此方法和上面的方法一样,写法不同,怎么用随个人 *喜好,我比较喜欢用这种方法,如下: */ const Axios = axios.create({ baseURL:baseURL , // 后台服务地址 timeout: 60000, // 请求超时时间1分钟 responseType: "json", withCredentials: false // 是否允许带cookie这些 }); /* 3.设置拦截器 */ /*如果不是用创建实例的方式配置,那么下面的Axios都要换成axios,也就是文件开头你用import引入axios 时定义的变量*/ Axios.interceptors.request.use((config) => { // 发送请求前进行拦截 // 可在此处配置请求头信息 // config.headers["appkey"] ="..."; // config.headers["token"] ="..."; console.log("======interceptors====="); console.log(config); if (config.method == "post") { /*数据转换: axios post方式默认是json格式提交数据,如果使用application/x-www-form-urlencoded数据格式提交,要用qs.stringify()进行转换,个人建议不在拦截器中全局配置,因为不够灵活,还有一点是,如果 设置了重新请求的配置,那么重新请求时,请求体中的config里面的传参就会被再次进行qs.stringify()转 换,会使得参数丢失,造成请求失败。*/ config.data = qs.stringify(config.data) } return config; },(error) =>{ //console.log("错误的传参", 'fail'); return Promise.reject(error) }) // Axios.interceptors.response.use((res) =>{ // // 请求响应后拦截 // if(res.status == 200){ // 对响应数据做些事 // //alert("提交成功") // return Promise.resolve(res) // } // return res; // }, (error) => { // //alert("网络异常!") 404等问题可以在这里处理 // return Promise.reject(error) // }) export default Axios
如果浏览器报这个错:: No 'Access-Control-Allow-Origin' header
这是个跨域问题:client/server同一个ip不同端口或者相同的端口不同的ip或者ip、端口都不同(个人理解)
vue-cli2解决方法(3.x网上也有),在
config/index.js文件中的proxyTable添加如下配置:
proxyTable: { '/': { target: 'http://localhost:8082/myproject', //你要访问的服务器域名 changeOrigin: true, //允许跨域 pathRewrite: { '^/': '' } } },
axios中的baseURL 不能配置否则就不用这个代理的配置了。