Alby's blog

世上没有巧合,只有巧合的假象。

0%

Axios 同时支持下载和 JSON 数据格式

一、概述

AJAX 请求服务器可能返回不同的数据格式,比如返回文件或 JSON 格式————当文件由于某些原因不可下载时返回 JSON 格式。

二、问题

Axios 的核心还是使用的是 XMLHttpRequest 。可以设置 XMLHttpRequest 对象的 responseType 属性以改变从服务器端获取的预期响应。可接受的值为空字符串(默认)、arraybufferblobjsontextXMLHttpRequest 对象的 response 属性依赖于 responseType,数据类型可能是 ArrayBuffer, Blob, Document, JSONstring

三、解决方案

1. 服务端

当服务器可能返回文件或 JSON 时,Content-Type 分别设置为 application/octet-streamapplication/json
如果返回文件的 Content-Type 不为 application/octet-stream,则客户端在使用 js-file-download 时要设置成相同的。

2. 客户端

Axios 发送请求指定为 responseTypearraybuffer,如果发现 Response 的 Content-Typeapplication/json,则先将返回的数据转换成字符串,然后再转换为 JSON

Axios 发送请求不要指定 responseTypeblob,因为没有方法同步地blob 转换为字符串或 JSON 。

Axios response interceptor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const SuccessCode = 200
const httpClient = axios.create()

httpClient.interceptors.response.use(
response => {
if (response.headers['content-type'].indexOf('json') === -1) {
// 返回的数据不是 json (或是 json 但服务器的 content-type 设置不准确)
return response
}

// 仅处理 json 数据
let json
if (response.request.responseType === 'arraybuffer' && response.data.toString() === '[object ArrayBuffer]') {
// 返回的数据是 arraybuffer,内容是 json
// 备注:可能内容不是 json,这里暂未处理
const text = Buffer.from(response.data).toString('utf8')
console.log(text)
json = JSON.parse(text)
} else {
// 备注:不是 arraybuffer 可能会是 blob 等,这里暂未处理
json = response.data
}

if (json && json.url) {
top.location = json.url
} else if (json && json.code !== SuccessCode) {
console.log(json)
return Promise.reject(new Error(json.message))
}
return response
},
error => {
// 返回 response 里的错误信息
return Promise.reject(error)
}
)

使用:

1
2
3
4
5
6
7
8
9
10
11

const fileDownload = require('js-file-download')

httpClient.post(url, params, {
responseType: 'arraybuffer'
}).then(response => {
fileDownload(response.data, 'test.xlsx')
}, error => {
console.log(error.message)
})

参考资料