二进制流转换成图片文件 及 不同请求responseType设置问题
背景:
要求通过接口获取第三方平台传输的文件流,无需下载,获取后显示、或转成文件自动上传到当前平台媒资库。
image展示主要可以用base64格式或者url格式
后端传过来的数据直接请求格式为:
打印在控制平台——data为一串乱码:
网络请求转换后格式
二进制图片转化后格式为:
- arrayBuffer类型:
- blob类型:
fetch请求:
fetch中图片请求配置:
- 可使用response.blob();转化请求格式
// fetch图片请求
export const config = {
http: 'http://000.00.00.000:39000', // 请求服务地址
baseURL: '/imm/v1', // baseurl地址
}
// 根据接口要求,拼接fetch请求完整URL
export function getFetchShowcase(data) {
const query = new URLSearchParams(data.params).toString();
return `${config.http}${config.baseURL}/model/${data.uid}/showcase?${query}`
}
let showcaseParams = { // 入参
uid: uidC || '0',
params:{
filename: item,
}
};
const picUrl = getFetchShowcase(showcaseParams); // 请求URL
// fetch请求
fetch(picUrl)
.then(response => {
if (!response.ok) {
throw new Error(`请求错误! 当前: ${response.status}`);
}
return response.blob();
})
.then(data =>{
const imageUrl = URL.createObjectURL(data);
picListUrl.value.push({ name:item, imageUrl });
}
) // 处理数据
.catch(error => console.error('Error:', error)); // 处理错误
fetch简介
使用:
fetch 是现代浏览器原生支持的 API
======async与await使用======使用 x-www-form-urlencoded 格式======
async function postFetch() {
const data = {
name: 'John Doe',
age: 30
};
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
//'Content-Type': 'application/json'
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},
body: JSON.stringify(data)
});
const result = await response.json();
console.log(result);
}
postFetch();
===========请求使用 FormData 格式===========
async function postFormData() {
const formData = new FormData();
formData.append('name', 'John');
formData.append('age', '30');
const response = await fetch('https://api.example.com/data', {
method: 'POST',
body: formData,
});
const result = await response.json();
console.log(result);
}
postFormData();
fetch 请求返回的是一个 Response 对象。它包含多个属性和方法:
response解析不同的数据格式方法
response.json()
方法可将数据解析为 JSON 格式。
response.text()
方法可将数据解析为 纯文本。
response.blob()
返回二进制 Blob 对象。
response.arrayBuffer()
返回 ArrayBuffer 对象。
response属性
response.ok
布尔值,表示请求是否成功
response.status
返回 HTTP 状态码(例如:200 表示成功)
response.url
返回请求的 URL 地址
fetch请求的配置选项参数说明:
method:请求方法,如GET, POST, PUT, DELETE等。
headers:请求头部,用于设置Content-Type或其他自定义头部。
body:请求体,通常用于POST或PUT请求。
mode:请求模式,如cors, no-cors, same-origin。
credentials:是否发送cookies,如include, omit, same-origin。抱歉,出了点小问题,请稍后重试
axios请求:
存在现象:
在axios中,由于大部分项目会有二次封装。
!!!
在图片请求配置过程中,会出现responseType不起作用的现象。
import axios from "axios";
import { ElMessage } from "element-plus";
const config = {
// 默认地址请求地址,可在 .env.** 文件中修改
baseURL: import.meta.env.VITE_APP_BASE_API,
// 设置超时时间
timeout: 5000,
//post请求头
headers: {
"Content-Type": "application/json;charset=UTF-8;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
},
};
const service = axios.create(config);
service.interceptors.request.use(
(config) => {
return config;
},
(error) => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
(response) => {
if (response.status !== 200 || response.data.retcode == false) {
ElMessage({
message: response.data.retmsg || "系统未知错误",
type: "error",
});
return Promise.reject(new Error(response.data.retmsg || "系统未知错误"));
}
return response;
},
(error) => {
// ElMessageBox(JSON.stringify(error), "请求异常", {
// confirmButtonText: "确定",
// callback: console.log(error),
// });
return Promise.reject(new Error(error));
}
);
export default {
post(url, data) {
return new Promise((resolve, reject) => {
service({
method: "post",
url,
data: data,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
},
get(url, data) {
return new Promise((resolve, reject) => {
service({
method: "get",
url,
params: data,
responseType:'arraybuffer',
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
},
put(url, data) {
return new Promise((resolve, reject) => {
service({
method: "put",
url,
data: data,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
},
delete(url, data) {
return new Promise((resolve, reject) => {
service({
method: "delete",
url,
params: data,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
},
getImage(url, data) {
return new Promise((resolve, reject) => {
service({
method: "get",
url,
params: data,
responseType:'blob',
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
},
};
拓展——运用axios配置:
import axios from 'axios';
// 创建一个自定义的Axios实例
const customAxios = axios.create({
baseURL: 'https://your-api-base-url.com', // 你的API基础URL
timeout: 10000, // 请求超时时间
// 可以在这里设置默认的headers,但通常Content-Type会在每个请求中单独设置
// headers: { 'Content-Type': 'application/json' }, // 不建议在这里设置,因为可能需要根据请求类型变化
responseType: 'json', // 设置默认的responseType为json,如果你总是期望返回JSON数据
});
// 添加一个请求拦截器,用于在每个请求发送之前设置Content-Type
customAxios.interceptors.request.use(config => {
// 根据请求类型(GET, POST, PUT, DELETE等)或其他条件设置Content-Type
if (config.method === 'post' || config.method === 'put') {
config.headers['Content-Type'] = 'application/json'; // 对于POST和PUT请求,通常使用application/json
} else if (config.method === 'get' || config.method === 'delete') {
// 对于GET和DELETE请求,通常不需要设置Content-Type,因为你不会在请求体中发送数据
// 但如果服务器有特殊要求,可以在这里设置
// config.headers['Content-Type'] = 'application/x-www-form-urlencoded'; // 例如,如果需要发送表单数据
}
// 其他配置或逻辑...
return config;
}, error => {
// 处理请求错误
return Promise.reject(error);
});
// 添加一个响应拦截器,用于处理响应数据(虽然responseType已经在实例中设置了,但这里可以处理其他逻辑)
customAxios.interceptors.response.use(response => {
// 对响应数据做些什么
return response.data; // 通常你会返回response.data,因为它已经根据你的responseType被解析了
}, error => {
// 处理响应错误
return Promise.reject(error);
});
// 使用你的自定义Axios实例进行请求
customAxios.post('/endpoint', { key: 'value' })
.then(data => {
console.log(data); // 这里data应该是一个已经解析为JavaScript对象的JSON数据
})
.catch(error => {
console.error('Error:', error);
});
axios中图片请求配置:
-
配置
responseType:'blob'
-
删除请求头Content-Type配置 /
或请求头添加配置:Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
注意请求头是否配置默认 application/json,此配置接受不到除JSON的其它数据格式。 -
如果上序无法解决,查看axios版本兼容问题。
headers: {
"Content-Type": "application/json;charset=UTF-8;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}
axios简介:
responseType类型拓展
responseType用于指定服务器响应的数据类型。
常见的数据类型有:“arraybuffer”、“blob”、“document”、“formdata”、“json”、“text”、"stream"等。
拓展——responseType
responseType 是一个配置选项,通常用于AJAX请求(如使用fetch
API或XMLHttpRequest对象)中,用于指定预期
的响应类型
。
常见的responseType值包括:
arraybuffer
:返回数据作为ArrayBuffer对象
blob
:返回数据作为Blob对象
document
:返回数据作为Document对象(如HTML)
json
:返回数据作为解析后的JSON对象
text
:返回数据作为字符串
''(空字符串)
:默认行为,根据Content-Type自动解析
拓展——Content-Type
Content-Type 是一个HTTP头部,用于指示资源的MIME类型。它告诉客户端(如浏览器)
服务器返回
的内容
是什么格式。
常见的Content-Type值包括:
text/html
:HTML文档
application/json
:JSON格式的数据
application/xml
:XML格式的数据
text/plain
:纯文本
application/x-www-form-urlencoded
:表单数据(键值对)
multipart/form-data
:用于文件上传的表单数据
二进制与图片格式转换
blob类型数据转显示URL
拿到blob类型二进制数据后,只需执行如下转换:
const imageUrl = URL.createObjectURL(blob);
拓展-----------
查阅大佬资料https://blog.csdn.net/sinat_36359516/article/details/119641566
现象1: new blob([])后文件大小跟原文件大小不一样
原因:获取的文件流乱码导致的
// 创建一个Blob对象
var blob = new Blob([binaryData], {type: 'image/png'}); // 这里的type依据你的实际图片格式而定
// 创建一个URL指向Blob对象
var imageUrl = URL.createObjectURL(blob);
现象2:在使用mock时
mock模块会影响原生的ajax请求,使得服务器返回的blob类型变成乱码
可以看到overrideMimeType()中mockjs初始化的时候给拦截响应设置了responseType:’’
解决:
A.别用 mockjs了,找到引入mockjs的地方import、require给注释掉;
B.改下源码 dist/mock.js
大约在 8683 行,加一行代码
this.custom.xhr.responseType = this.responseType
C.但离谱的是,我的项目mock.js是在index.html中引入的,一旦注释掉,使用Mock.mock(url, ‘get’, (res) => { })的文件就会报错,于是我们看了一下报错,Mock is undefined,此时应该是明白了,没有引入当然会报错了,于是我们把使用了mockjs来模拟请求后端接口获得数据的文件注释掉了,即用到Mock.mock(url, ‘get’, (res) => { })的文件,测试一下,终于搞定了。
arrayBuffer类型数据转显示URL
arrayBuffer将二进制流转成URL
// 假设 arrayBuffer 是你已有的包含图片数据的 ArrayBuffer
const arrayBuffer = ...; // 你的 ArrayBuffer 数据
const mimeType = 'image/png'; // 根据你的图片数据设置正确的 MIME 类型
// 将 ArrayBuffer 转换为 Blob
const blob = new Blob([arrayBuffer], { type: mimeType });
// 创建一个可以访问该 Blob 的 URL
const url = URL.createObjectURL(blob);
arrayBuffer将二进制流转换为Base64编码
axios({
method: 'get',
url: 'https://example.com/api/get-image', // 请求的图片接口地址
responseType: 'arraybuffer' // 设置响应类型为arraybuffer
})
.then(function (response) {
this.src = 'data:image/jpeg;base64,' + this.arrayBufferToBase64(response.data);
})
.catch(function (error) {
console.error('获取图片失败', error);
});
arrayBufferToBase64函数的主要步骤如下:
- 创建一个Uint8Array对象,用于表示arraybuffer数据。
- 遍历数组中的每一个字节,将其转换为对应的二进制字符。
- 最后使用window.btoa方法将二进制字符数据转换为Base64格式的字符串。
arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
拓展-----
在请求到的图片数据中,可能存在多种不同的格式(如jpeg、png等),我们需要根据后端返回的Content-Type来判断并动态设置前缀。例如:
const contentType = response.headers['content-type'];
this.src = `data:${contentType};base64,` + this.arrayBufferToBase64(response.data);
这样可以确保兼容多种图片格式,增强代码的通用性。
小程序中ArrayBuffer、base64、url互转
buffer转base64:
that.setData({
imgBase64: wx.arrayBufferToBase64(res.result.buffer)
})
buffer转url:
const fsm = wx.getFileSystemManager();
const FILE_BASE_NAME = 'qrcode_base64src';
const filePath = wx.env.USER_DATA_PATH + '/' + FILE_BASE_NAME + '.jpg';
fsm.writeFile({
filePath,
data: res.result.buffer,
encoding: 'binary',
success() {
that.setData({
resultImage: filePath //结果图片
})
},
fail() {},
})
url转arraybuffer
wx.chooseImage({
success: function(res) {
const fsm = wx.getFileSystemManager();
fsm.readFile({
filePath:res.tempFilePaths[0],
success:function(res){
//转换成功
var arrayBuffer = res.data
},
fail:function(e){}
})
}
})
base64转arrayBuffer
var arrayBuffer = wx.base64ToArrayBuffer(imgBase64)
拓展——图片相关优化处理
此部分转自链接:https://blog.csdn.net/qq_37241934/article/details/108639364/
缓存优化
如果图片在一段时间内不会改变,可以考虑对获取的图片进行缓存,减少重复请求:
if (!this.src) {
// 没有缓存图片,才发送请求
this.getImage();
}
图片懒加载
在一些页面中,可能需要显示多张图片。如果这些图片全部通过二进制流加载且直接显示,可能会消耗较多带宽和内存。因此,可以考虑对图片实现懒加载,只有当图片即将进入用户视口时才发起请求。
结合IntersectionObserver API可以实现图片懒加载:
mounted() {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.getImage();
}
});
});
observer.observe(this.$refs.imageElement);
}
封装请求逻辑
为了使代码更加简洁和模块化,可以将请求图片的逻辑封装到一个服务中,这样不仅提高代码复用性,还能更好地管理请求:
import axios from 'axios';
export function fetchImage(url) {
return axios({
method: 'get',
url,
responseType: 'arraybuffer'
}).then(response => {
return 'data:image/jpeg;base64,' + arrayBufferToBase64(response.data);
});
}
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
这样在组件中只需调用fetchImage(url)即可获取图片数据,代码更加清晰易读。