内容简介:上回还真的有同学提到了这个问题,感谢细心的你。@_noob其实是没任何问题的,只不过看起来违背了常见的结构,像是有问题。其实是上文为了照顾初学者,怕大家因为麻烦而放弃,并没有一次性改的“看起来那么复杂”,我们来填下坑。为了照顾没有实时跟着我连载的同学,每一章的代码单独发布在我的
上回还真的有同学提到了这个问题,感谢细心的你。@_noob
其实是没任何问题的,只不过看起来违背了常见的结构,像是有问题。其实是上文为了照顾初学者,怕大家因为麻烦而放弃,并没有一次性改的“看起来那么复杂”,我们来填下坑。
为了照顾没有实时跟着我连载的同学,每一章的代码单独发布在我的 Github 博客,不进行覆盖更新 [除非代码有错误进行修改],这样避免了 2019 年小明同学望着前两章和 Github 最终版本代码发呆 ( release 也不是特别友好)
我们把上文的 renderer/src 改成比较容易理解的 src/renderer ,这其实是一个编程习惯问题。
上文 renderer/src 的问题
eslint-config-alloy : 想写出更规范的代码可以参考这个规则
下面进入本章正题
axios
使用了 vue 的你,发现 Vue 居然不能发请求,于是你 Google 了下,发现可以用 Vue-Resource。 你去问别人 Vue-Resource 怎么样,他说不要用 Vue-Resource,因为 Vue-Resource 官方已经停止维护了,你应该用 Axios、或者 fetch。但是我们想拥抱 ES6 排除掉了 ES5的fetch(当然也有ES6-fetch),这里我们使用 Axios!
Tips
这里呢也科普一下:什么时候依赖需要放到 dependencies、什么时候依赖需要放到 devDependencies:
devDependencies:顾名思义,仅在开发(dev)模式下如:webpack. 、 .loader、eslint、babel、打包后部署时完全用不到的、仅在开发需要 编译、检测、转换 的放在这里。 dependencies:例如:axios、chart、js-cookie、less、lodash、underscore等运行时的库或 工具 类等相关依赖我们要放在这里
不过基本不用担心,官网都会提供 start 说明,但是我们要大概明白意思,不要机械般的 copy。
引入 Axios
- 直接玩最新的
2018-09-28 截图npmjs.com
- 添加依赖
"dependencies": { "axios": "^0.18.0" } 复制代码
基于上一章内容,别忘了重新 npm i 下载一下
还记得我们自动生成的 vue 主页面脚本 main.js吗?
封装axios
我们在 src/renderer/utils
建立一个 request.js
在这个请求脚本中,对 Axios 做一些必要的封装,大概内容是用 拦截器 axios.interceptors 对请求和响应做些拦截,定义一下 API 的前缀,处理一些常见的 HTTP 状态码。
- interceptors 文档
我尽可能的为大家写了详细的注释。
// src/renderer/utils/request.js import axios from 'axios' //这里一般指后端项目API的前缀,例如 /baidu/*/*/1.api /mi/*/*/2.api const BASE_API = "" export function axiosIntercept(Vue, router) { const axiosIntercept = axios.create({ baseURL: BASE_API }) //http request 拦截器 一般用来在请求前塞一些全局的配置、或开启一些 css 加载动画 axios.interceptors.request.use( (config) => { // 判断是否存在token,如果存在的话,则每个http header都加上token // if (store.getters.accessToken) { // console.log(store.getters.accessToken) // config.headers.Authorization = `token ${store.getters.accessToken}`; // } //todo:加载动画 //若有需求可以处理一下 post 亦或改变post传输格式 if (config.method === 'post') { }; return config; }, function (err) { return Promise.reject(err); }); //http response 拦截器 一般用来根据一些后端协议特殊返回值做一些处理,例如:权限方面、404... 或关闭一些 css 加载动画 axiosIntercept.interceptors.response.use(function (response) { // todo: 暂停加载动画 return response; }, function (err) { //捕获异常 if (err.response) { switch (err.response.status) { case 401: // do something 这里我们写完后端做好约束再完善 } } return Promise.reject(err); }); return axiosIntercept; } 复制代码
大家还记得我们用 vue-cli 生成的 vue 主页脚本 main.js 吧,这里我们需要对 Axios 和 Vue 做一个耦合。
// src/renderer/main.js import axios from 'axios' import { axiosIntercept } from './utils/request' // 将Axios扩展到Vue原型链中 Vue.prototype.$http = axiosIntercept(Vue) 复制代码
这样我们在写业务逻辑,直接在 Vue 的上下文中 使用 this.$http 来发送请求。既实现了拦截、又实现了状态的共享。
知其然,知其所以然
- 这样做的意义在哪?
节省代码量,让代码更加易读
- 为什么?
扩展到原型链,使 Axios 运行时共享 Vue 原型链的内容,减少了很多指代 Vue 的临时变量
- 举个栗子
传统情况
import axios from 'axios' new Vue({ data: { user: "" }, created: function () { //此时作用域在 Vue 上,缓存起来,要依赖此变量 let _this = this; axios.get("/user/getUserInfo/" + userName).then(res => { if (res.data.code === 200) { //此时作用域在axios上,拿不到vue绑定的值,只能借助刚才缓存的_this上下文 _this.data.user = res.data.user } }); } }) 复制代码
代理之后
new Vue({ data: { user: "" }, created: function () { // axios 成为了 vue 的原型链一部分,共享vue状态。 this.$http.get("/user/getUserInfo/" + userName).then(res => { if (res.data.code === 200) { //注意,axios回调,应该尽量使用箭头函数,可以继承父类上下文,否则类似闭包,还是无法共享变量、 // 更优雅了一些 this.data.user = res.data.user } }); } }) 复制代码
不懂 prototype 可以翻翻我以前写的文章
proxy
先简单弄一下,为前后分离打个小铺垫
webPack
- webPack 的别名
resolve: { extensions: ['.js', '.vue', '.json'], alias: { '@': resolve('src/renderer'), } }, 复制代码
为了使用起来更加优雅,可以为每个常用的目录都建立别名
resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src/renderer'), 'assets': resolve('src/renderer/assets'), 'components': resolve('src/renderer/components'), 'container': resolve('src/renderer/container'), 'utils': resolve('src/renderer/utils') } }, 复制代码
生产和开发的跨域问题
dev 是开发时启动的指令 build 是预发布时 webPack 打包的指令
假设笔者只是一个前端,通常呢,在开发调试过程当中,无法避免需要与后端的同学进行 API 的对接,那也就难免会出现跨域问题。当然传统 javaWeb 不需要跨域,(ip 域 端口 任何一个不同皆为跨域) 在 DEV 模式调试中,我们都是尽量选择前端环境规避跨域问题,而不会去额外搭建 nginx 或更改后端代码。
跨域只是针对 JavaScript 的,因为开发者认为浏览器上的脚本是不安全的。
既然我们的 vue 项目是 node 全家桶,依靠 node、webPack 编译 我们直接配置 node 的 proxyTable 作为开发的代理器,这样最简单,依次配置,团队受益。
cnode 掘金 社区 API 举例
cnodejs.org/api 上边cnode 的 API 是可以随意调用的,因为后端做了处理。
看看掘金的: xiaoce-timeline-api-ms.juejin.im/v1/getListB… 请求一下,不出意外浏览器做了跨域报警。
哦,我们适配一下 node 代理
官方例子在这: vuejs-templates.github.io/webpack/pro…
扩展一下 proxyTable:
proxyTable: [{ //拦截所有v1开头的xhr请求 context: ['/v1'], target: "https://xiaoce-timeline-api-ms.juejin.im", cookieDomainRewrite: { // 不用cookie }, changeOrigin: true,//重点,此处本地就会虚拟一个服务替我们接受或转发请求 secure: false }], 复制代码
再次发送请求。
- 愉快的拿到了数据
这样,前后分离的项目可以这样借助 swagger 测试接口,不需要骚扰任何人。实现自己的业务逻辑,简单实现一点。
代码:
// blog/index.vue <template> <div class="Blog"> <h1>{{ msg }}</h1> <div v-for="(blog,index) in blogList" v-bind:key="index"> <h3 > <a :href="`https://juejin.im/book/`+blog.id" > <span>{{blog.title}}</span> </a> </h3> </div> </div> </template> <script> export default { name: "Blog", data() { return { msg: "掘金小册一览", blogList: [] }; }, created() { this.getBlog(); }, methods: { getBlog() { this.$http.get("/v1/getListByLastTime?src=web&pageNum=1").then(res => { this.blogList = res.data.d; }); } } }; </script> 复制代码
发布
- 扫盲
写完代码之后部署到线上,是不会在线上 clone 代码之后 Npm run dev 的:laughing:,那样会有太多太多的垃圾依赖,为用户带来了灾难性的网络请求,通常借助webPack打包之后发布到服务器的web服务当中。
运行
npm run build 复制代码
打包目录是之前配置的webpack
好了,很多人直接双击 index.html 是不行的。
Tip: built files are meant to be served over an HTTP server. Opening index.html over file:// won't work.
需要 http 服务启动,可以扔到本地或服务器的 nginx、apache、tomcat等容器测试,我通常使用 python 启动一个 http 服务来运行(脚本地址)、当然,自己 ide 支持 http 启动也可以。
生产中的跨域
生产当中,因为前端后端必然不同端口,避免跨域,通常使用 nginx 的正向/反向代理作为跨域的手段。(并非负载均衡,两个概念)
server { listen 80; server_name localhost; location ^~ /v1 { proxy_pass https://xiaoce-timeline-api-ms.juejin.im;#代理。 proxy_set_header X-Real-IP $remote_addr;#转发客户端真实IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } } 复制代码
简单配置一下就可以了,不多讲,前端同学了解一下就可以了,nginx 能干的事情还有很多。
API 的规范化
你是否为了找某一个业务的接口头痛 你是否还在使用全局搜索找自己的接口 你是否某一个接口不同组件重复写了多次 整理一下自己的接口吧,像上文的 router 一样整齐的划分吧。
/renderer 下建立一个 api 的文件夹
webpack.base.conf.js 添加一条 api 的别名,方便我们日后大量调用
'api': resolve('src/renderer/api') 复制代码
我们建立 /renderer/api/juejin.js
import axios from 'axios' let Api = Function() Api.prototype = { getBlog(page, fn) { axios.get(`/v1/getListByLastTime?src=web&pageNum=${page}`).then(res => { // if (res.data.code === 200) { fn(res.data) // } }).error() } } export default new Api() 复制代码
修改一下我们刚才 /blog/index.vue 的 Axios 请求:
- 先引入 api
import juejin from "@/api/juejin"; 复制代码
注掉之前离散的 axios ,使用从 api 中定义过的 XHR 请求数据。
getBlog() { // this.$http.get("/v1/getListByLastTime?src=web&pageNum=1").then(res => { // this.blogList = res.data.d; // }); juejin.getBlog("1", response => { this.blogList = response.d; }); } 复制代码
OK,很多同学不理解,本来简单的事情为什么搞复杂了?其实这样不复杂,看起来还很清晰,倘若一个大项目上千个请求,不仅重复导致代码覆盖率低,看起来还很乱,不利于团队协作。本系列文章在带领大家前后分离的基础上,会为大家提供更多有利于团队的开发方式,养成良好习惯。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端微服务在字节跳动的打磨与应用
- 博客园细节美化打磨
- 精心打磨的 Act-1.8.8 出炉了
- AAAI 2020 | 用渐进打磨获得最佳的显著性目标检测结果
- PHP 框架 QueryPHP 1.0 正式版,四年打磨生产可用!
- 搜狗获全球口语翻译大赛冠军 多模型融合细节打磨成制胜法宝
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。