终止请求:abort()
一个简单的ajax,仅供入门学习使用
/**
* 调用SendAjax,调用接口
* @param {obj} object method:请求方式,url:地址,success:请求成功回调
*/
function SendAjax (obj) {
function createAJAX () {
let ajax = null
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest() // iE7以上
} else if (window.ActiveXObject) {
const ActiveXObject = window.ActiveXObject // iE6到iE5以下
ajax = new ActiveXObject('Microsoft.XMLHTTP')
} else {
alert('请升级浏览器')
}
return ajax
}
var ajax = createAJAX() // 创建一个ajax对象
ajax.open(obj.method, obj.url, true)
ajax.onreadystatechange = function () {
if (ajax.readyState === 4 && ajax.status === 200) {
obj.success(ajax.responseText)
}
}
if (obj.method === 'get') {
ajax.send(null)
} else if (obj.method === 'post') {
ajax.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
let str = ''
let v = ''
let f = false
for (var attr in obj.data) {
str += v + attr + '=' + obj.data[attr]
v = '&'
if (obj.data[attr] !== '') {
f = true
} else if (obj.data[attr] === '') {
f = false
return f
}
}
if (f) {
ajax.send(str)
}
}
}
export default SendAjax()
跨越:协议,域名,端口号不同,引发的安全请求问题
img
标签的src
可以解决上面的问题,但是请求回来的是图片信息,不能使用
同理还有video
标签等等
script
标签的src请求回来的是js代码信息,可以作为跨越解决方案
但是返回的信息如何获取?可以通过函数调用的方式获取,调用函数,传入入参
script
标签script
标签前进给bodycallback(数据信息)
的形式返回给浏览器// 粗劣残暴的解决方案
// params可以优化成对象
/**
* param { url } 跨越请求的地址
* param { params } 拼接的字符串入参
* param { fn } 获取返回结果的回调
*/
export default function jsonp(url, params, fn) {
let callbackName = `fn${+new Date()}`
window[callbackName] = (res) => { fn(res) }
let script = document.createElement('script')
script.type = "text/javascript";
script.src = `${url}?callback=${callbackName}&${params}`
document.body.appendChild(script)
document.body.removeChild(script)
}
实现功能:
post
请求,get
请求等基本请求
请求前拦截,请求后拦击
设置全局devServe
识别标志(baseUrl
),设置全局timeout
响应时间
拦截前操作:
添加请求网关,有需要自定义的使用自定义,没有使用全局网关
添加token,有不需要tiken的可以添加自定义标识,进行判断
设置下载文件名称,有自定义下载文件名称,赋值给全局变量。
单独处理报错,有自定义处理报错消息,修改全局变量 处理报错标识
单独设置超时,有自定义的使用自定义,没有就使用全局超时时间
参数转get,保持请求函数统一性,get和params入参方式统一
参数转表单形式,处理参数以表单形式传入
获取请求进度,添加获取下载/上传进度条的构造函数
取消请求,取消当前进行的全部请求
(⭐:未设计和验证)为了在切换路由时或特别情况时主动中断请求
请求后拦截:
根据res.header
判断文件类型,进行预处理。
如:二进制流图片,可以直接使用,二进制图片转图片url,进行处理,然后返回处理结果
根据全局变量-自定义报错处理,判断是否需要直接返回请求结果
判断是否为未登录
是:统一报错,return false
,并调整到登录页面
判断后端返回的状态码是否通过判断
是:返回结果,return data
否:进入下一步
未通过判断,是否存在单独设置获取错误表示
是:return Promise.reject(data)
否:进行统一报错,return false
其他请求处理
post
请求形式下载get
请求形式下载json
转xlsx
下载功能post
文件和数据分开上传post
文件和数据合成formData
一起上传xlsx
转json
导入功能可以直接复制,建议将代码看完后,修给后使用
import axios from "axios";
import Qs from "qs";
import * as xlsx from "xlsx";
// 构造axios封装函数
function setAjaxHttp({
preFix,
baseURL,
timeout,
fileTypes,
Message,
handleResponse,
}) {
// 定义入口网关
const prefix = preFix || "";
const ajax = axios.create(); // 实例化一个axios
if (!preFix && baseURL) ajax.defaults.baseURL = baseURL; // 设置接口的域名和端口号
let setFileName = false; // 自定义文件下载名称
let gainError = false; // 单独处理错误标记
// 添加请求webpack-serve前缀/接口请求网关
function getBaseUrl(config) {
// 单独接口使用 请求自定义 服务器地址、端口、接口网关
if (config.data && config.data.baseUrl) {
config.url = config.data.baseUrl + config.url;
// 如果存在自定义下载文件名称
delete config.data.baseUrl;
} else {
// 否则使用环境变量判断得到的,走代理域名和端口
config.url = prefix + config.url;
}
return config;
}
// 设置token
function setToken(config) {
if (config.data && config.data.setToken) {
ajax.thisToken = config.data.setToken;
delete config.data.setToken;
return config;
}
}
// 添加token
function addToken(config) {
// 如果注明不需要token,这不添加token,直接返回config对象
if (config.data && config.data.withoutToken) {
delete config.data.withoutToken;
return config;
}
// 添加token
if (ajax?.thisToken && !config.headers?.token)
config.headers.token = ajax?.thisToken;
return config;
}
// 设置下载文件名称
function setDownFileName(config) {
setFileName = false;
// 如果存在 自定义 下载文件名称
if (config.data && config.data.setFileName) {
setFileName = config.data.setFileName;
delete config.data.setFileName;
}
return config;
}
// 单独处理错误标记
function setGainError(config) {
gainError = false;
// 如果存在 单独处理错误标识
if (config.data && config.data.gainError) {
gainError = config.data.gainError;
delete config.data.gainError;
}
return config;
}
// 单独设置超时时间
function setTimeOut(config) {
if (config.data && config.data.timeout) {
config.timeout = config.data.timeout || timeout;
delete config.data.timeout;
} else {
config.timeout = timeout;
}
return config;
}
// 转换get入参
function paramsSwitchToQuery(config) {
if (config.method === 'get') {
config.params = config.data || config.params;
config.data = null;
config.paramsSerializer = (params) => {
return Qs.stringify(params, { arrayFormat: 'brackets', strictNullHandling: true })
}
}
return config
}
// 获取进度条
function getAjaxRange(config) {
if (config.data && config.data.getRange) {
// 获取上传/下载进度条
let getRange = config.data.getRange;
delete config.data.getRange;
// 将上传的formData直接当作入参
if (config.data.formData) config.data = config.data.formData;
const fn = (progress) => {
// 有时候拿不到total值,这个值总是为0
// 只要设置后台的代码 response.setContentLengthLong(文件长度); 就可以了
getRange?.fn(Math.round((progress.loaded / progress.total) * 100));
};
if (getRange.type === "upload") config.onUploadProgress = fn;
if (getRange.type === "download") config.onDownloadProgress = fn;
}
return config;
}
// 转换为表单格式请求
function switchToFormData(config) {
// 如果需要转换成表单格式
if (config.data && config.data.transform) {
delete config.data.transform;
// 通过axios提供的transformRequest 修改入参格式
config.transformRequest = [
function (data) {
return Qs.stringify(data);
},
];
}
return config;
}
// 取消请求
const source = axios.CancelToken.source(); // 创建CancelToken
function cancelAjax(config) {
// 切换页面时取消请求 主要是优化
config.cancelToken = source.token;
return config;
}
// 使用案例:
// 注解:没必要详细到单独接口,毕竟web端接口量特别大,精准控制不合适
// 外部引入,调用ajax.cancelAjax,取消请求
ajax.cancelAjax = function (word = "Operation canceled by the user") {
source.cancel(word);
};
// 请求拦截 - 在发送请求之前做些什么
ajax.interceptors.request.use(
(config) => {
getBaseUrl(config); // 添加请求webpack-serve前缀/接口请求网关
setToken(config);
addToken(config); // 添加token
setDownFileName(config); // 设置下载文件名称
setGainError(config); // 单独处理错误标记
setTimeOut(config); // 单独设置超时时间
getAjaxRange(config); // 获取进度条
paramsSwitchToQuery(config) // 转换get入参
switchToFormData(config); // 转换为表单格式请求
cancelAjax(config); // 取消请求
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截
ajax.interceptors.response.use(
(res) => {
if (res?.header) {
// 处理流数据的时候,直接返回结果,用于下载
if (res.headers["content-type"].includes("image")) {
return getBase64Image(res.data);
} else if (fileTypes.includes(res.headers["content-type"])) {
return res;
}
}
// 调用传入的参数处理函数
return handleResponse(res?.data, gainError);
},
(error = "error") => {
if (error.stack.indexOf("timeout") > -1) {
Message && Message(error);
} else if (error.msg !== undefined) {
Message && Message(error);
}
return Promise.reject(error);
}
);
// 图片 二进制转图片url
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
var dataURL = canvas.toDataURL("image/" + ext);
return dataURL;
}
// post请求下载文件
// 默认download
ajax.download = function (url, params = {}) {
return ajax({
method: "post",
url,
data: {
...params,
getRange: {
fn: params.getRange || null,
type: "download",
},
},
headers: {
"X-Requested-With": "XMLHttpRequest",
},
responseType: "blob",
})
.then(disposeRes)
.catch((error) => {
return Promise.reject(error);
});
};
// get请求下载文件
ajax.downloadFileByGet = function (url, params = {}) {
return ajax({
method: "get",
url,
params: {
...params,
getRange: {
fn: params.getRange || null,
type: "download",
},
},
headers: {
"X-Requested-With": "XMLHttpRequest",
},
responseType: "blob",
})
.then(disposeRes)
.catch((error) => {
return Promise.reject(error);
});
};
// 将json数据转换.xlsx下载
// 待验证
/**
*
* @param { json } JsonData // json数据
* 案例:[{name: '旭大王', age: 12}, {name: '旭小王', age: 21}]
* @param { object } columns // 表头设置
* 对应案例:{ name: '姓名', age: '年龄' }
* @param { string } FileName // 文件名称
*/
ajax.jsonToXlsx = function (JsonData, columns, FileName) {
// json数据转excel
// 先转化json
var arrData =
typeof JsonData !== "object" ? JSON.parse(JsonData) : JsonData;
var excel = "";
var row = "";
// 设置表头
var keys = Object.keys(JsonData[0]);
keys.forEach(function (item) {
if (columns) row += "" + columns[item] + " ";
else row += "" + item + " ";
});
// 换行
excel += row + " ";
// 设置数据
for (var i = 0; i < arrData.length; i++) {
let row = "";
for (var index in arrData[i]) {
row += "" + arrData[i][index] + " ";
}
excel += row + " ";
}
excel += "
";
var excelFile =
"";
excelFile +=
'';
excelFile +=
';
excelFile += '; charset=UTF-8">';
excelFile += "";
excelFile += "";
excelFile += "";
excelFile += "";
excelFile += excel;
excelFile += "";
excelFile += "";
var uri =
"data:application/vnd.ms-excel;charset=utf-8," +
encodeURIComponent(excelFile);
var link = document.createElement("a");
link.href = uri;
link.style = "visibility:hidden";
link.download = FileName + ".xls";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
// 处理下载文件返回数据
function disposeRes(res) {
// 获取文件名称
let fileName = res.headers["content-disposition"].split("filename=")[1];
if (setFileName) fileName = setFileName;
// 解码文件名称
fileName = decodeURI(fileName);
// 将后端返回的二进制流转换为下载链接
let blobUrl = new Blob([res.data], {
type: "application/octet-stream;charset=utf-8",
});
if ("download" in document.createElement("a")) {
// 动态生成a变迁,使用a标签的download属性完成下载
const eLink = document.createElement("a");
const href = URL.createObjectURL(blobUrl);
eLink.download = fileName;
eLink.style.display = "none";
eLink.href = href;
document.body.appendChild(eLink);
eLink.click();
URL.revokeObjectURL(href);
document.body.removeChild(eLink);
} else {
// 如果a标签没有download属性,直接调用window属性保存到本地
navigator.msSaveBlob(blobUrl, fileName);
}
}
/**
* 文件上传
* 获取到上传的文件,并进行入参拼接
*/
// 文件上传(可批量携带formData, 文件和数据分开传递, 且文件流入参key是固定的file)
ajax.uploadFile = function (url, file, data = {}) {
// 创建FormData对象
const formData = new FormData();
// 创建进度条控制对象
let getRange = {
fn: data.getRange || null,
type: "upload",
};
delete data.getRange;
let upLoadTimeout = timeout;
// 将获取的文件添加到formData,不同组件上次的文件可能不同
if (file instanceof Array) {
file.forEach((item) => {
formData.append("file", item.raw, item.name);
});
} else {
formData.append("file", file.raw, file.name);
}
// 如果存在传递参数
if (Object.toString.call.apply(data) === "[object Object]") {
if (data.timeout) {
upLoadTimeout = data.timeout;
delete data.timeout;
}
for (let key in data) {
formData.append(`${key}`, data[key]);
}
}
let config = {
headers: {
"Content-Type": "multipart/form-data",
},
timeout: upLoadTimeout,
};
return ajax.post(url, { getRange, formData }, config);
};
// 携带参数上传(参数和文件一起传递)
ajax.uploadFileWithPost = function (url, params = {}) {
const formData = new FormData();
let getRange = null;
if (
params.getRange &&
Object.prototype.toString.call(params.getRange) === "[object Function]"
) {
getRange = {
fn: params.getRange,
type: "upload",
};
delete params.getRange;
}
let upLoadTimeout = timeout;
if (params.timeout) {
upLoadTimeout = params.timeout;
delete params.timeout;
}
appendParamsToFormData(formData, params); // 对象递归判断转平级
let config = {
headers: {
"Content-Type": "multipart/form-data",
},
timeout: upLoadTimeout,
};
return ajax.post(url, { getRange, formData }, config);
};
// 将.xlsx转换为json数据导入
/**
*
* @param { file } file // 上传的文件
* @param { array } columns // 表头设置,
* 案例[{label: '名称', key: 'name'}, {label: '年龄', key: 'age'}]
* label与xlsx的表头对应,key为转换的json数据的keyName
* @returns 返回转换的json
*/
ajax.xlsxToJson = async function (file, columns) {
return new Promise((resolve) => {
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
var wb = xlsx.read(data, { type: "binary" });
var xlsxData = xlsx.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
// wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
// wb.Sheets[Sheet名]获取第一个Sheet的数据
xlsxData = xlsxData.map((data) => {
let obj = {};
for (let key in data) {
let findObj = columns.find((item) => item.label === key);
if (typeof data[key] === "string") {
obj[findObj.key] = data[key].replace(/(^\s*)|(\s*$)/g, ""); // 去除左右空格
} else obj[findObj.key] = data[key];
}
return obj;
});
resolve(xlsxData);
};
reader.readAsBinaryString(file);
});
};
// 对象递归判断转平级
function appendParamsToFormData(formData, params) {
for (let key in params) {
let value = params[key];
let prototypeStr = Object.prototype.toString.call(value);
if (prototypeStr === "[object File]") {
// 更具具体key值传递文件流,文件名称需要打印输出判断
formData.append(key, value, value.name);
// 将内部对象值递归转出化平级
} else if (prototypeStr === "[object Object]") {
appendParamsToFormData(formData, value);
} else {
formData.append(key, value);
}
}
}
return ajax;
}
export default setAjaxHttp;
// 下面是使用案例
import setAjaxHttp from "../utils/http";
import router from "@/router/index";
import { MessageBox, Message } from "element-ui";
// 统一处理错误函数
function handleResponse(data, gainError) {
if (data.status !== 1) {
if (gainError) return Promise.reject(data);
// 401: 无效token; 402: 异地登陆; 403: token过期;
let isTokenError = ["401", "402", "403"].includes(data.status);
if (isTokenError) {
MessageBox &&
MessageBox.confirm(
"您已退出登录,您可以取消以留在此页面,或重新登录",
"重新登陆",
{
confirmButtonText: "重新登录",
cancelButtonText: "取消",
type: "warning",
}
).then(() => {
router.push("/login");
});
return Promise.reject(data);
}
}
return data;
}
// 导出实例化后的ajax
const http = setAjaxHttp({
preFix: "/api",
timeout: 5000,
fileTypes: [
"multipart/octet-stream;charset=utf-8",
"multipart/form-data",
"multipart/octet-stream",
"octets/stream;charset=UTF-8",
],
Message,
handleResponse,
});
// 下面是http使用案例
export const usersFind = (params) => http.get("/users/find", { params });
export const usersAdd = (params) => http.post("/users/add", params);
创建链接对象:var Socket = new WebSocket(url, [protocol] );
var ws = new WebSocket('ws://localhost:8001');
url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
只读属性:
console.log(Socket.readyState)
0 - 表示连接尚未建立, 1 - 表示连接已建立, 2 - 表示连接正在进行关闭,3 - 表示连接已经关闭
console.log(Socket.bufferedAmount)
正在加载的队列
绑定事件:
Socket.onopen = fn
: 连接建立时触发Socket.onmessage = fn
:客户端接收服务端数据时触发Socket.onerror = fn
: 通信发生错误时触发 Socket.onclose = fn
:连接关闭时触发方法:
Socket.send(src)
:使用连接发送数据Socket.close()
:关闭连接示例
var ws = new WebSocket("ws://localhost:9998/echo");
ws.onopen = function() {
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("发送数据");
alert("数据发送中...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("数据已接收...");
};
ws.onclose = function() {
// 关闭 websocket
alert("连接已关闭...");
};
进阶
发生图片数据
ws.onmessage = function (e) {
mess.innerHTML = "连接成功"
document.querySelector(".kuang").onclick = function (e) {
var time = new Date();
ws.send(time + " game1点击了“" + e.target.innerHTML + "”");
}
var inputElement = document.getElementById("file");
inputElement.onchange = function (e) {
var file = (e.target.files)[0]
ws.send(file);
}
}
/**
请求函数封装
使用格式
@param { String } api // 接口名称
@params data // 入参合集, 含有:入参,自定义网关前缀,是否携带token(boolean),是否表单提交(boolean),单独定义的timeout,自定义responseType
request.post(api, { params, [baseUrl], [withoutToken], [transform], [timeout], [responseType] })
其他同理使用,文件上传可以将入参放在formData关键字,也可以直接入参
入参文件可以使用files关键字传递文件,按照uni-app官方上传文件文档操作即可
目录:
入参加密
自定义修改baseUrl
自定义是否添加token
是否转换为表单请求
单独接口自定义timeout
自定义responseType
处理文件上传
数据请求
*/
import store from '../store/index' // 引入vuex, 处理token,token加密,请求操作函数
import { router } from '../router' // 引入router,token失效跳转登录页面
import refreshToken from './refreshToken' // 刷新token函数(预留函数)
import Qs from 'qs' // 引入Qs
// showError: 全局错误信息处理函数
// requestListAdd: 请求操作函数队列新增, get读取,del删除
import { showError, requestListAdd, requestListGet, requestListDel, checkDataType } from './utils'
const prefix = process.env.NODE_ENV === 'development' ? '/api' : '/mpas' // 通过环境变量判断请求前缀
const refreshLogin = false // 不自动刷新登录状态
const timeoutDefault = 1000 * 60 // 预设超时时间
export default {
get(api, data) { return this.theRequest({ api, data, method: "get" }) }, // 进行get请求
post(api, data) { return this.theRequest({ api, data }) }, // 进行post请求
upload(api, data) { return this.theRequest({ api, data, useType: "uploadFile" }) }, // 进行post文件上传
download(api, data) { return this.theRequest({ api, data, useType: "downloadFile" }) }, // 进行post文件下载
// 自定义修改baseUrl
addBaseUrl(args) {
// 特定自定义过服务识别和网关接口,使用自定义的
if (args.data && args.data.baseUrl) {
args.url = args.data.baseUrl + args.url
delete args.data.baseUrl
} else {
// 否则使用环境变量判断得到的
args.url = prefix + args.url
}
return args
},
// 自定义是否添加token
addToken(args) {
// 如果注明不需要token,这不添加token,直接返回config对象
if (args.data && args?.data?.withoutToken) {
delete args?.data?.withoutToken
return args
} else if (store.state.app.token) {
if (refreshLogin) refreshToken() // 是否刷新token
// 添加token - 这里没有将token放在请求头
args.url = args.url + '?id_token=' + store.state.app.token
}
return args
},
// 是否转换为表单请求
switchToFormData(args) {
if (args.data && args.data.transform) {
delete args.data.transform
args.data = Qs.stringify(args.data)
}
return args
},
// 单独接口自定义timeout
setTimeout(args) {
if (args.data && args.data.timeout) {
args.timeout = args.data.timeout
delete args.data.timeout
} else {
args.timeout = timeoutDefault
}
return args
},
// 自定义responseType
setDataType(args) {
if (args.data && args.data.responseType) {
args.responseType = args.data.responseType
delete args.data.responseType
}
return args
},
// 处理文件上传
setFormData(args, useType) {
if (useType !== 'uploadFile') return args
// 处理文件
if (args.data && args.data.files) {
args.files = args.data.files
delete args.data.files
}
// 将参数用formData上传(虽然没有必要)
if (args.data) {
args.formData = args.data
delete args.data
}
return args
},
// 数据请求
theRequest({ api, data, method = "post", useType = "request" }) {
let _this = this // 修改this名称
let gainError = false // 是否需要自定义处理错误
let isDirect = false // 是否直接返回结果不进行拦截处理
let getFunction = uni[useType] // 同态获取请求方法
let requestTask = '' // 用来获取请求中操作函数
// 需要返回的promise
const obj = new Promise((resolve, reject) => {
// 进行接口请求前拦截
uni.addInterceptor(useType, {
// 接口请求前拦截
invoke(args) {
_this.addBaseUrl(args) // 自定义修改baseUrl
_this.addToken(args) // 自定义是否添加token
_this.switchToFormData(args) // 是否转换为表单请求
_this.setTimeout(args) // 自定义timeout
_this.setDataType(args) // 自定义responseType
_this.setFormData(args, useType) // 处理文件上传
_this.encryption(args, method) // 自动入参加密
// 是否需要全局拦截
if (args.data && args.data?.gainError) {
gainError = args?.data?.gainError
// 每次调用theRequest会刷新gainError,每个接口的状态不一样
// 不用担心gainError状态持续为true
delete args?.data?.gainError
}
// 是否需要直接返回结果
if (args.data && args.data?.isDirect) {
isDirect = args?.data?.isDirect
delete args?.data?.isDirect
}
},
// 接口链接成功函数 - 接口请求后拦截
success: (res) => {
// 删除当前完成接口控制函数
requestListDel(api)
if (isDirect) return resolve(res) // 直接返回结果
if (res.statusCode === 401) {
uni.showToast({ icon: 'none', title: '登录过期'})
router.push('/pages/login/index')
reject(res)
} else if (res.statusCode === 200) {
// 如果返回的接口为json字符串
if (checkDataType(res.data, 'string')) res.data = JSON.parse(res.data)
const { code, msg, errMsg } = res.data
if (code === 1) resolve(res) // 接口请求成功
else if (gainError) reject(res)
else uni.showToast({ icon: 'none', title: msg || errMsg || "网络链接异常" })
} else {
// 结果返回的请求错误信息
if (gainError) reject(res)
else {
const { msg, errMsg } = res.data
uni.showToast({ icon: 'none', title: msg || errMsg || "网络链接异常" })
}
}
},
// 接口链接失败函数
fail: (err) => {
if (gainError) reject(err)
else showError(err) // 注意,后续如果需要接口请求超时,在showError里添加超时判断
}
})
// 进行接口请求
requestTask = getFunction({
url: api,
data,
method,
header: {}
})
// 将操作函数存储到store中
let isExist = requestListGet(api)
if (!isExist) { // 如果没有,进行新增。
requestListAdd({ key: api, fn: requestTask })
} else { // 如果有,停止前一个, 由于停止后即删除,所以需要重新新增
if (isExist?.abort) isExist?.abort()
requestListDel(api)
requestListAdd({ key: api, fn: requestTask })
}
// 清除接口请求前拦截 - 监听类似于定时器,必须要进行清除
uni.removeInterceptor(useType)
})
// 返回promise
return obj
}
}
无论是返回图片链接还是图片下载,都必须设置下面的步骤
无论是git
还是post请求
,请求都必须设置responseType: 'blob',
上一步不设置,无法获取正确的二进制流数据结果
二进制图片转换
let binaryData = [];
binaryData.push(blob);
// 其实window.URL.createObjectURL(blob)就可以了
// Chrome更新后不支持这种用法, 需要添加上面的东西。
link.href = window.URL.createObjectURL(new Blob(binaryData));
文件资源
let fileName = res.headers['content-disposition'].split('filename=')[1]
fileName = decodeURI(fileName)
let blob = new Blob([res.data], { type: 'application/octet-stream;charset=utf-8' })
const href = URL.createObjectURL(blob)
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = href
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(href)
document.body.removeChild(elink)