Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
使用npm:
npm install axios
使用 bower:
bower install axios
使用 cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
首先,Content-Type被指定为 application/x-www-form-urlencoded;其次,提交的表单数据会转换为键值对并按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。 另外,如利用AJAX 提交数据时,也可使用这种方式。例如 jQuery,Content-Type 默认值都是”application/x-www-form-urlencoded;charset=utf-8”。
另一个常见的 POST 数据提交的方式, Form 表单的 enctype 设置为multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符(这就是boundary的作用)分开,类似我们上面Content-Type中的例子。 由于这种方式将数据有很多部分,它既可以上传键值对,也可以上传文件,甚至多个文件。当上传的字段是文件时,会有Content-Type来说明文件类型;Content-disposition,用来说明字段的一些信息。每部分都是以 –boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(字段、文本或二进制等)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 –boundary– 标示结束。
Content-Type: application/json 作为响应头比较常见。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串,其中一个好处就是JSON 格式支持比键值对复杂得多的结构化数据。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持JSON.stringify,服务端语言也都有处理 JSON 的函数,使用起来没有困难。 Google 的 AngularJS 中的 Ajax 功能,默认就是提交 JSON 字符串。
XML的作用不言而喻,用于传输和存储数据,它非常适合万维网传输,提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据,在JSON出现之前是业界一大标准(当然现在也是),相比JSON的优缺点大家有兴趣可以上网search。因此,在POST提交数据时,xml类型也是不可缺少的一种,虽然一般场景上使用JSON可能更轻巧、灵活。
在Chrome浏览器的Postman工具中,还可以看到”binary“这一类型,指的就是一些二进制文件类型。如application/pdf,指定了特定二进制文件的MIME类型。就像对于text文件类型若没有特定的子类型(subtype),就使用 text/plain。类似的,二进制文件没有特定或已知的 subtype,即使用 application/octet-stream,这是应用程序文件的默认值,一般很少直接使用 。
对于application/octet-stream,只能提交二进制,而且只能提交一个二进制,如果提交文件的话,只能提交一个文件,后台接收参数只能有一个,而且只能是流(或者字节数组)。
很多web服务器使用默认的 application/octet-stream 来发送未知类型。出于一些安全原因,对于这些资源浏览器不允许设置一些自定义默认操作,导致用户必须存储到本地以使用。一般来说,设置正确的MIME类型很重要。
** 在src 目录下创建一个utils 工具文件夹,创建一个request.ts 文件。 ** request.ts 文件内容如下
import axios, { AxiosRequestConfig } from 'axios'
// 设置请求参数
const timeOut = 1000 * 1000 * 60
const protocol = location.protocol
const BaseUrl = "http://XXXX"
// 创建实例
const service = axios.create({
baseURL: BaseUrl,
timeout: timeOut,
})
// 添加请求拦截器
service.interceptors.request.use((config: any) => {
config.headers = {'content-type': 'application/json'}
return config
}), (error: any) => {
return Promise.reject(error)
}
// 添加响应拦截器
service.interceptors.response.use((response: any) => {
return response.data
}), (error: any) => {
return Promise.reject(error)
}
//添加request 类
class request {
// get 请求
static get(url: any, params: any) {
let config: AxiosRequestConfig = {
method: 'get',
params: params,
url: url
}
return service(url, config)
}
// post 请求
static post(url: any, params: any) {
let config: AxiosRequestConfig = {
method: 'post',
data: params,
url: url
}
return service(url, config)
}
}
export default request
在src文件下创建api文件夹,用作api 的统一管理
import request from '../utils/request'
export class TestService {
test(params: any) {
return request.get('/XXXX/XXX', params)
}
}
在项目中调用
async handleTest() {
let params = {
id: 123
}
let result = await this.service.test(params)
if (result) {
console.log('result.data')
}
}
实现创建一个js接口文件,统一管理接口。 然后在该文件中引入get()和post()
//api.js
import {get, post} from './http.js';
export const login = p => post('http://www.xxxx.com/api/', p)
在这里我们定义了一个login方法,这个方法有一个参数p,它是请求该接口时携带的参数对象。另一个url就是我们请求接口的地址。
这样,我们就写好了一个api接口了,接下来就是在页面方法中引用。
//login.vue
import {login} from '@/request/api';
export default {
name: 'login',
methods: {
onLogin() {
login({
userName: 123,
passWord: xxxx,
}).then(res = > {
console.log(res)
})
}
}
}
以上就是最基本的axios封装啦
// 商品模块 product.js
const product = {
sku: {
list: '/product/product/speclist',
options: '/product/product/options'
}
}
export default product
// 公用请求模块 common.js
const common = {
region: {
provinces: '/region/region/list',
cities: '/region/region/list'
},
upload: {
image: '/product/product/upload'
}
}
export default common
发送请求的时候只需要指定key(sku/list),如:this.$ajax('sku/list', param);假定axios设置的baseURL是http://prod.storm.com/api/
,那么最终的请求地址:http://prod.storm.com/api/product/product/speclist
使用webpack提供的require.context将src/api/url下后缀为js的所有文件引入,并整理出一个对象。
let urls = {}
const req = require.context('./url', false, /\.js$/)
const requireAll = requireContext => requireContext.keys().map(i => {
let url = requireContext(i)
Object.assign(urls, url.default)
})
requireAll(req)
export default urls
整合common.js & product.js,最终得到的对象如下:
urls = {
sku: {
list: '/product/product/speclist',
options: '/product/product/options'
},
region: {
provinces: '/region/region/list',
cities: '/region/region/list'
},
upload: {
image: '/product/product/upload'
}
}
// 注意:模块名product和common没有了,所以需要注意命名的唯一,以免覆盖。
import axios from 'axios'
import qs from 'qs'
import jsd from 'js-file-download'
import store from '@/store'
import urlObj from './requireURLs'
import { Message, MessageBox } from 'element-ui'
import { getToken } from '@/utils/auth'
const service = axios.create({
baseURL: `${process.env.BASE_API}/api/`, // 不同环境(dev/prod/test)使用不同的baseURL
timeout: 5000
})
service.interceptors.request.use(
config => {
// 上传文件时,config.data的数据类型是FormData,
// qs.stringify(FormData)的结果是空字符串,导致接口报**参数为空**的错误
if (config.method === 'post' && config.data.constructor !== FormData) {
config.data = qs.stringify(config.data)
}
if (store.getters.token) {
config.headers.common['Auth-Token'] = getToken()
// Auth-Token 登录过期后,重新登录不传token
if (!config.headers.common['Auth-Token']) {
delete config.headers.common['Auth-Token']
}
}
return config
},
error => {
Promise.reject(error)
}
)
service.interceptors.response.use(
response => {
const res = response.data // 后台会把{ code, data, msg }返回到response.data中
if (response.headers['content-type'].indexOf('application/vnd.ms-excel') !== -1) {
// 通过请求接口下载Excel,由于后台返回的数据中(res)没有code(我也不知道为什么,反正后台就说没有),所以我只好通过响应头的content-type判断了
// 下载接口返回的response header如下(后台把文件名放在Content-Disposition中(filename))
// Content-Disposition: attachment; filename=20190323211209.csv
// Content-Type: application/vnd.ms-excel;charset=GBK
let fileName = response.headers['content-disposition'].split('=')[1]
jsd(res, fileName)
return
}
if (res.code === 0) { // 和后台约定code:0代表请求成功
return res
} else {
if (res.code === 18500) { // 和后台约定code:18500代表token未过期,但是被更新了
handleLogin('您已被登出,请重新登录')
} else if (res.code === 18501) { // 和后台约定code:18500代表token过期
handleLogin('登录已失效,请重新登录')
} else {
// 统一处理接口的报错信息,如果需要具体到页面去处理,可以和后台另外约定一个code
Message({
message: res.msg,
type: 'error',
duration: 3 * 1000
})
}
return Promise.reject(res)
}
},
error => {
let data = error.response.data
Message({
message: data.msg,
type: 'error',
duration: 3 * 1000
})
return Promise.reject(data)
}
)
const handleLogin = title => {
MessageBox.confirm(title, '提示', {
confirmButtonText: '重新登录',
showCancelButton: false,
showClose: false,
type: 'warning'
}).then(() => {
store.dispatch('FedLogout').then(() => {
location.reload()
})
})
}
const ajax = (path, data = {}, options = {}) => {
// 如果path以http开头指定了一个url,直接用;否则就去遍历步骤3中的urls对象。如下:
// this.$ajax('http://test.storm.com'),url = 'http://test.storm.com'
// this.$ajax('sku/list'),url = '/product/product/speclist'
let url = path.indexOf('http') === -1 ? path.split('/').reduce((o, k) => {
return o[k]
}, urlObj) : path
let method = options.method || 'post'
let params = { url, method }
// 由于我司后台提供的接口大都是post和get,所以只考虑了这两种请求方式
if (options.method === 'get') {
Object.assign(params, { params: data }, options)
} else {
// post
Object.assign(params, { data }, options)
}
return service(params)
}
export default ajax
// ajaxPlugin.js
import ajax from '@/api/ajax'
let ajaxPlugin = {}
ajaxPlugin.install = Vue => {
Vue.prototype.$ajax = ajax
}
export default ajaxPlugin
// main.js
import ajaxPlugin from '@/plugins/ajaxPlugin'
Vue.use(ajaxPlugin)
this.$ajax('sku/list').then(res => {})
更多相关知识和参考文章来源可以关注我的博客站点
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。