在实际开发 SPA 应用时,一般和后端都会采用异步接口进行数据交互。传统情况下,我 们常用 jQuery 的 $.ajax() 方法来做异步请求。但 Vue.js 并不依赖于 jQuery,我们也并不需 要为了异步请求这个功能就额外引用 jQuery。所以这里就和大家介绍下 Vue.js 的插件 Vue- resouce,它同样对异步请求进行了封装,方便我们同服务端进行数据的交互。
npm install vue-resource
//main.js
import VueResource from "vue-resource"
Vue.use(VueResource)
安装好 Vue-resource 之后,在 Vue 组件中,我们就可以通过 this.$http 或者使用全局 变量 Vue.http 发起异步请求,例如:
VueResource组件:
<template>
<div>
<h2>vue-resource testh2>
<button type="button" @click="test">点击发送请求button>
<p>{{msg}}p>
div>
template>
<script>
export default {
name: 'ResourceTest',
data () {
return {
msg: ''
}
},
methods: {
test() {
//这段代码需要运行在服务器环境中
this.$http
.get("/hello")
.then(function(rep){//成功的回调函数
this.msg = rep.data
}, function(rep){//失败的回调函数
alert(rep.data)
})
}
}
}
script>
app.vue
<template>
<div id="app">
<router-link to="/">首页router-link>
<router-link to="/test">testrouter-link>
<router-view/>
div>
template>
<script>
export default {
name: 'App'
}
script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
style>
路由:
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import ResourceTest from '@/components/ResourceTest';
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/test',
name: 'ResourceTest',
component: ResourceTest
}
]
})
配置代理,在config/index.js中:
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {//代理
'/hello': {
target: 'http://localhost',//代理到本地80端口
changeOrigin: true,
pathRewrite: {
'^/hello': '/hello'
}
}
},
...
}
启动后端服务,go语言:
import (
"fmt"
"net/http"
)
/*
*/
func main() {
server := &http.Server{
Addr: "0.0.0.0:80",
}
http.HandleFunc("/hello", hello)
server.ListenAndServe()
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
this.$http 可以直接当做函数来调用,我们以下面这个例子来对其选项进行说明:
this.$http({
url: '/api/list',//url访问路径
method: '',//HTTP请求方法,例如GET,POST,PUT,DELETE等
body: {},//request中的body数据,值可以为对象,String类型,也可以是FormData对象
params: {},//get方法时url上的参数,例如/api/list?page=1
headers: {}, //可以设置request的header属性
timeout: 1500,//请求超时时长,单位为毫秒,如果设置为0的话则没有超时时长
before: function(request){},//请求发出前调用的函数,可以在此对request进行修改
progress: function(event){},//上传图片、音频等文件时的进度,event对象会包含上传文件的总大小和已上传大小,通常可以用来作为进度条效果
credentials: boolean,//默认情况下,跨域请求不提供凭据 (cookie、HTTP 认证及客户端 SSL 证明等 )。该选项可以通过将 XMLHttpRequest 的 withCredentials 属性设置为 true, 即可以指定某个请求强制发送凭据。如果服务器接收带凭据的请求,会用 Access-Control-Allow- Credentials: trueHTTP 头部来响应
emulateHTTP: boolean,// 设置为true后,PUT/PATCH/DELETE请求将被修改成 POST 请求,并设置 header 属性 X-HTTP-Method-Override。常用于服务端不支持 REST 写法时
emulateJSON: boolean //设置为 true 后,会把 request body 以 application/ x-www-form-urlencoded 的形式发送,相当于 form 表单提交。此时 http 中的 header 的 content- type 即为 application/x-www-form-urlencoded。常用于服务器端未使用 application/json 编码时
})
此外,this.$http 还可以直接调用 api 方法,相当于提供了一些快捷方式,例如:
get(url, [options])
head(url, [options])
delete(url, [options])
jsonp(url, [options])
post(url, [body], [options])
put(url, [body], [options])
patch(url, [body], [options])
以上方法均可以采用 this.$http.get(url, options)
或 Vue.http.get(url, options)
这样类 似的形式进行调用。
在发起异步请求后,我们可以采用 this.$http.get(...).then()
的方式处理返回值。.then() 接受一个 response 的参数,具体的属性和方法如下。
url: response 的原始 url。
body :response 的 body 数据,可以为 Object,Blob,或者 String 类型。
headers :response 的 Headers 对象。
ok: 布尔值,当 HTTP 状态码在 200 和 299 之间时为 true。
status: response 的 HTTP 状态码。
statusText: response 的 HTTP 状态描述。
//另外还包含以下三种 api 方法。
text(): Promise 类型,把 response body 解析成字符串。
json(): Promise 类型,把 response body 解析成 json 对象。
blob(): Promise 类型,把 response body 解析成 blob 对象,即二进制文件,多用于图片、音视频等文件处理。
拦截器主要作用于给请求添加全局功能,例如身份验证、错误处理等,在请求发送给服 务器之前或服务器返回时对 request/response 进行拦截修改,完成业务逻辑后再传递给下一 步骤。Vue-resource 也提供了拦截器的具体实现方式,例如:
Vue.http.interceptors.push(function(request, next) {
// 修改请求
request.method = 'POST';
// 继续进入下一个拦截器
next();
});
也可以对返回的 response 进行处理:
Vue.http.interceptors.push(function(request, next){
request.method = 'POST';
next(function(response) {
// 修改response
response.body = '...';
});
});
或者直接拦截返回 response,并不向后端发送请求:
Vue.http.interceptors.push(function(request, next) {
// body 可自己定义,request.respondWith 会将其封装成 response,并赋值到 response.body 上
next(request.respondWith(body, {
status: 403,
statusText: 'Not Allowed
}));
});
Vue-resource 提供了一种与 RESTful API 风格所匹配的写法,通过全局变量 Vue. resource 或者组件实例中的 this.$resource 对某个符合 RESTful 格式的 url 进行封装,使得 开发者能够直接使用增删改查等基础操作,而不用自己再额外编写接口。
我们先大致说明下 RESTful API :这是一种设计风格而不是标准,只是提供了一组设 计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可 以更简洁,更有层次,更易于实现缓存等机制。在这种风格中,每个 url 路径代表一种资源
(resource),所以路径中不推荐有动词,只能有名词,而且所用的名词往往与数据库的表格 名对应,且一般采取复数的形式命名。而对于资源的具体操作类型,则由 HTTP 动词表示, 即 GET/POST/PUT/PATCH/DELETE 等。
我们以产品 products 为例,设计出的 api 即为。
GET /api/products, :获取所有产品列表。
POST /api/products :新建一个产品。
GET /api/products/:id :获取某个指定产品信息。
PUT /api/products/:id :更新某个指定产品信息。
DELETE /api/products/:id :删除某个指定产品。
GET /api/products/:id/items :获取某个指定产品下的 items 信息列表。 在需要对信息进行过滤的情况下,以 query 参数形式进行筛选,例如:
GET /api/products?limit=10&offset=10&sortBy=name
简单说明完 RESTful 后,结合 this.$resource,我们可以使用与后端接口对接:
var products = this.$resource('/api/products{/id}');
// 相当于发起异步GET请求, 访问/api/products/1接口,获取指定产品信息
products
.get({ id : 1})
.then(function(rep) {
this.$set('products', rep.json());
})
// POST /api/products 参数为 data,新建一个产品
products
.save({}, data)
.then(function(rep) {
....
})
Vue-resource 提供了 6 个默认动作行为,分别为:
get: {method: 'GET'},
save: {method: 'POST'},
query: {method: 'GET'},
update: {method: 'PUT'},
remove: {method: 'DELETE'},
delete: {method: 'DELETE'}
除了默认行为外,Vue-resource 也允许我们自定义行为,例如:
var customActions = {
order : { method: 'POST', url : '/api/products{/id}/orders'} };
var products = this.$resource('/api/products{/id}');
// 即调用异步接口 POST /api/products/1/orders
products
.order({ id : 1})
.then(function(rep) { .... })
在编写 SPA 应用中,我们通常会把和后端做数据交互的方法封装成一个 Service 模块, 供不同的组件进行使用。我们可以新建一个文件夹 api,将 Service 模块集中起来,并按资源 进行分类。
以上述 products 资源为例:
// /api/products.js
const API_URL = '/api/products;
export default {
get(context, productId) {
return context.$http({
url : API_URL + '/' + productId,
method : 'get'
});
},
query(context, params) {
return context.$http({
url : API_URL,
params : params
})
}
.........
}
在组件中调用方式如下:
import productsSrv from './api/products.js';
var ProductDetail = Vue.component('product-detail', {
route : {
data : function(transition) {
productsSrv
.query(this, transition.to.params)
.then(function(rep) {
})
}
}
});