二进制流转换成图片文件 及 不同网络请求配置问题

背景:

要求通过接口获取第三方平台传输的文件流,无需下载,获取后显示、或转成文件自动上传到当前平台媒资库。
image展示主要可以用base64格式或者url格式

后端传过来的数据直接请求格式为:
在这里插入图片描述
打印在控制平台——data为一串乱码:
在这里插入图片描述

网络请求转换后格式

二进制图片转化后格式为:

  • arrayBuffer类型:
    在这里插入图片描述
  • blob类型:
    在这里插入图片描述

fetch请求:

fetch中图片请求配置:

  1. 可使用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

======asyncawait使用======使用 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)即可获取图片数据,代码更加清晰易读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值