当前位置: 首页 > news >正文

如何拦截响应内容并修改响应头

背景及需求描述

背景

记录分享下近期遇到并解决的困扰了比较久的问题:在不同系统微信生态发现同一个cos地址用window.open(url)打开在苹果和安卓设备的微信生态上表现不一致:对于文档类型,响应头Content-Type: application/pdf 在安卓微信上唤起浏览器下载弹窗;在ios微信、
safari等浏览器中则直接打开了该文档[出现这种差异的原因有懂的大佬欢迎指教~]。

要在ios设备中实现下载,需配置响应头Content-Type: application/octet-stream,但是该响应头在安卓微信内变成无法下载,提示“可在浏览器打开此网页来下载文件” 。

目前生产环境文档资源配置响应头Content-Type: application/octet-stream(为解决ios设备无法下载pdf), 最后是联系云厂商根据设备信息定制响应头解决了问题。但是在不直接向用户暴露出资源链接的情况下,前端其实也是可以通过“修改响应信息”达到相同效果的。

目标效果:
ios微信:

android微信:

浏览器弹出自带的下载确认弹窗
基于现状,我们的目的是:如何修改,实现安卓手机的微信中可以唤起跳转到浏览器的弹窗。

需求

我们知道: 用window.open(url)访问资源其实就是浏览器向该url指向的服务器发了个get请求,我们能用这种方法下载文件是因为:当使用window.open(url)时,浏览器会新开一个窗口或标签页(没带_self的情况)并尝试对给定的url进行导航/渲染,如果url指向的是个文件并且正确配置了响应头,浏览器会尝试直接下载该文件。
在这里插入图片描述

上面说的响应头包括:

Content-Type

Content-Type 实体头部用于指示资源的 MIME 类型 media type 。在响应中,Content-Type 标头告诉客户端实际返回的内容的内容类型。浏览器会在某些情况下进行 MIME 查找,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff。(引用自MDN)

这个响应头是用来告诉浏览器返回的内容是什么类型的。例如,它可以是“text/html”,表示内容是HTML文档;或者“image/jpeg”,表示内容是一张JPEG图片;

Content-Type: application/octet-stream告诉浏览器:服务器发送的响应内容是二进制格式的。它是一种通用的二进制文件类型,可以用于任何类型的二进制文件,包括文本文件、图片、音频、视频等。但是,由于它没有特定的子类型,因此它通常被视为应用程序文件的默认值,但在实际应用中很少直接使用。
Content-Type: application/pdf则是一种确定的二进制文件类型,用于指示服务器发送的响应内容是PDF格式的文件。当Content-Type设置为application/pdf时,浏览器会知道响应的内容是PDF文件,并采取相应的措施来正确地显示和渲染该文件(看浏览器能力,是解析还是下载,如果浏览器有内置pdf解析器或有解析插件就会解析该文档然后渲染文档内容)。

这个头部信息并不会直接决定内容是否被下载,而是告诉浏览器这是哪一种媒体类型,如何处理和显示这个内容,取决于浏览器本身的处理程序。
总结:这是个啥啥啥,怎么处理你浏览器自己决定。

Content-Disposition

在常规的 HTTP 应答中,Content-Disposition 响应标头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。(引用自MDN)

这个响应头告诉浏览器该如何处理返回的内容。 它可以被设置为“inline”或者“attachment”。一般情况下,当设置为“inline”时,内容通常会直接显示在浏览器窗口中(例如,图片或PDF文件)。而当设置为“attachment”时,浏览器通常会提示用户下载内容,而不是直接在浏览器窗口中显示。

总结:我要浏览器怎么怎么做。

也就是说,上述两个响应头影响了不同系统和浏览器中访问文件地址的表现,而我们在“背景”部分也介绍清楚了如何修改可以实现我们的需求,接下来便是实践部分:

显然我们直接用window.open(url)(或者直接用下面提到的a标签)的方法不能去拦截http请求/响应,当我们主动用这个url发个get请求就可以对请求和响应进行拦截,并做出相应的修改。下面我们拆解下任务:

  1. 实现前端发送一个http请求并下载资源;
  2. 拦截并改写http的response Header 【生产环境服务器配置响应头是Content-Type: application/otect-stream,因此修改安卓设备的响应头为Content-Type: application/pdf即可】

发送http请求并下载资源

需要注意的是,不管用哪一种请求库向资源发起请求这个动作本身并不会将文件下载到本地,我们只是主动像服务器发了个http请求、获取到响应的数据。我们需要额外的处理程序下载文件——常见的方法是创建一个a标签,设置其href属性为该资源url,并设置download属性,然后去触发它的点击事件。
设置了download属性的a标签click()事件被触发后,会默认导航到href属性所指向的url,也就是向url所指向的服务器发送请求。这是浏览器代理的,用其内置的下载机制。

请求到数据后,我们需要将返回的内容存放到一个容器里,然后创建一个url指向这个容器,这样我们需要用的时候就可以访问到而不用重复向服务器请求。下面我们将会用到js的Blob对象来充当这个容器,将response的内容转换成二进制数据放到这个blob实例对象中,并用URL.createObjectURL(blob)创建一个指向这个容器的变量(一个URL),在下载的时候直接用这个URL。

xhr方式

let url = "https://xxx?download_name=%23%E6%AF%8F%E6%97%A5%E7%9C%8B%E7%82%B92022.01.01.pdf";fetch(url).then(response => {return response.blob();})  .then(blob => {   // 处理二进制数据  const url = URL.createObjectURL(blob); //创建指向Blob对象实例的url//下面是下载程序const link = document.createElement('a');  link.href = url;  link.setAttribute('download', 'file.pdf'); // 下载文件的文件名  document.body.appendChild(link);  link.click();  document.body.removeChild(link);  })  .catch(error => console.error('下载文件时发生错误:', error));

axios方式

      const instance = axios.create();instance.get(url, { responseType: 'blob' }) .then(function (response) {  // 处理二进制数据  const blob = response.data;const url = window.URL.createObjectURL(blob); const link = document.createElement('a');  link.href = url;  link.setAttribute('download', 'file.pdf'); // 设置文件名  document.body.appendChild(link);  link.click();  setTimeout(() => {link.remove()}, 0)})  .catch(function (error) {  // 处理错误...});

我们已经实现了第一步的目标,并将该pdf下载到本地,下一步便是修改响应头。

修改响应头实现需求

我们知道前端请求库如axios有提供拦截器(interceptors),可以修改请求参数、请求标头、response的数据格式等。Fetch API也提供了修改请求头的方法:

//修改请求头
let headers = new Headers();  
headers.append('Content-Type', 'image/jpeg');  
headers.append('Another-Header', 'Another-Value');
fetch(url, {  method: 'GET',  headers: headers,  body: data  
})

经过多方实践发现,哪怕用拦截器,也只能修改响应体也就是返回的数据(如格式化一下、增加以下自定义属性等等,更多应用敬请自行探索),并不能直接拦截并修改响应头,对于额外设置的自定义response Header也不会生效

instance.interceptors.response.use(  response => {  // 对响应数据做点什么  response.headers['content-type'] = 'application/pdf'; response.headers['12-1'] = 'application/pdf'; return response;  },  error => {  return Promise.reject(error);  }  
); 

当我们尝试求改请求头content-type的值时会出现错误:TypeError: Failed to execute ‘set’ on ‘Headers’: Headers are immutable。
因为,在 Fetch API和Axios中,一旦请求被发送,就不能更改请求头。
得,看起来白忙活一场了,改不了一点。。。


当我尝试了解js的Blob对象,事情迎来了转机!!!
Blob对象包含两个只读属性size和type,这个type啊,是个字符串,表明该 Blob 对象所包含数据的 MIME 类型。如果类型未知,则该值为空字符串。emmmmmm MIME类型。。。不正和我们要修改的Content-Type对应上了嘛!愣着干啥,开干!


等等,只读属性。。。

改不了,改不了一点。。。
不死心又菜菜的我,还是去问ai
在这里插入图片描述

复制对象?好办法!我们拿到了响应的数据,搞个新的Blob对象,至于MIME类型重设下,触发下载的时候骗过浏览器不就好了嘛

const instance = axios.create();
instance.get(url, { responseType: 'blob' })  .then(function (response) { // 处理二进制数据  const blob = response.data;let newBlob = new Blob([blob], {type: 'application/pdf'}); // 重点在这里,在这里可对二进制数据进行处理,比如创建一个可下载的链接  const url = window.URL.createObjectURL(newBlob); //important!!!const link = document.createElement('a');  link.href = url;  link.setAttribute('download', 'file.pdf'); // 设置文件名  document.body.appendChild(link);  link.click();  setTimeout(() => {link.remove();URL.revokeObjectURL(url);  // 释放内存}, 0)
})  
.catch(function (error) {  // 处理错误  console.error(error);  
});

至此,我们已经实现了目标需求,在安卓微信上也可唤起跳转到浏览器的弹窗啦。
如前所述,这种方法适用于不暴露cos链接的情况,如果直接复制cos链接到安卓微信打开还是会弹出toast提示到浏览器去下载,这时候就需要去修改服务器的响应头了。去掉响应头中Content-Disposition的Utf-8也可绕过,看起来是不同浏览器接受对响应头中中文编码设置方式的差异造成的, 详见 https://stackoverflow.com/questions/18050718/utf-8-encoding-name-in-downloaded-file)

完结撒花,如有谬误,敬请指出~

关注我,一起学习前端知识【后面会介绍同时下载大量级文件、大文件如何处理,敬请期待~】
在这里插入图片描述

相关文章:

如何拦截响应内容并修改响应头

背景及需求描述 背景 记录分享下近期遇到并解决的困扰了比较久的问题:在不同系统微信生态发现同一个cos地址用window.open(url)打开在苹果和安卓设备的微信生态上表现不一致:对于文档类型,响应头Content-Type: application/pdf 在安卓微信上…...

分类预测 | Matlab实现WOA-GRU鲸鱼算法优化门控循环单元的数据多输入分类预测

分类预测 | Matlab实现WOA-GRU鲸鱼算法优化门控循环单元的数据多输入分类预测 目录 分类预测 | Matlab实现WOA-GRU鲸鱼算法优化门控循环单元的数据多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现WOA-GRU鲸鱼算法优化门控循环单元的数据多输入…...

特定深度节点链表

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 经典BFS与简单链表结合的题目。 #define MAX_DEPTH (1000)struct ListNode** listOfDepth(struct TreeNode* tree, int* returnSize) {*returnSize 0;struct ListNode **ans (…...

【css】背景换颜色

更换前 longin.html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>login</title><link href"/css/style.css" type"text/css" rel"stylesheet"><s…...

什么是美颜sdk?直播实时美颜sdk的工作流程和架构分析

在现代社交媒体和娱乐行业中&#xff0c;直播已经成为了一种受欢迎的娱乐形式&#xff0c;同时实时美颜也变得越来越重要。直播实时美颜SDK的工作流程和架构在这一领域起到了关键作用。本文将深入探讨这些SDK的内部机制&#xff0c;从而理解它们如何为用户提供出色的美颜效果。…...

第二证券:跌破3000点,热搜第一!

今天上午&#xff0c;“沪指开盘跌破3000点关口”冲上百度热搜榜榜首。 上午收盘&#xff0c;上证指数下跌0.27%&#xff0c;报2997.22点&#xff1b;深证成指下跌0.36%&#xff0c;创业板指下跌0.44%。 赛道股发力&#xff0c;光伏、风电、新能源轿车等板块盘中冲高。房地产…...

IJCAI2023【基于双曲空间探索的非独立同分布联邦学习】

1、介绍汇报的主题及汇报者 2、粗略介绍面临的挑战及出发点 3、介绍一下预备知识 4、解决方案 5、总览 6、实验设置 7、实验 8、结论...

实现Linux下Word转PDF、Java调用命令方式

使用 LibreOffice 实现 Word 转 PDF 和 Java 调用命令 1、 安装 LibreOffice 外网安装 # 一键安装 yum install -y libreoffice # 验证版本 libreoffice --version # Warning: -version is deprecated. Use --version instead. # LibreOffice 7.5.6.2 f654817fb68d6d4600d7…...

Java并发-06-AQS(AbstractQueuedSynchronizer)相关

1-概述 AQS全称是 AbstractQueuedSynchronizer&#xff0c;是阻塞式锁和相关的同步器工具的框架。同步器的设计是基于模板方法模式的&#xff0c;也就是说&#xff0c;使用者需要继承同步器并重写指定的方法&#xff0c;随后将同步器组合在自定义同步组件的实现中&#xff0c;并…...

【Python接口自动化】--深入了解HTTP接口基本组成和网页构建原理

引言 Python接口自动化有着广泛的应用场景&#xff0c;但是在实际使用过程中&#xff0c;可能会出现一些问题。比如&#xff0c;你不知道HTTP接口的基本构成&#xff0c;也不清楚网页是如何构建的。 这时&#xff0c;你就需要深入了解HTTP接口的基本组成和网页构建原理。通过本…...

window mysql5.7.27 启用SSL openssl mysql_ssl_rsa_setup

应客户监管部门要求 mysql必须要启用SSL。由于mysql安装在window上&#xff0c;启用过程中遇到了不少的坑&#xff0c;在此记录一下。 安装openssl 如果已经安装过可跳过此步 https://slproweb.com/download/Win64OpenSSL-1_1_1w.msi复制到浏览器下载后安装即可。如果需要其他…...

性能测试-JMeter分布式测试及其详细步骤

性能测试概要 性能测试是软件测试中的一种&#xff0c;它可以衡量系统的稳定性、扩展性、可靠性、速度和资源使用。它可以发现性能瓶颈&#xff0c;确保能满足业务需求。很多系统都需要做性能测试&#xff0c;如Web应用、数据库和操作系统等。 性能测试种类非常多&#xff0c…...

学习gin-vue-admin之创建api和swagger

文章目录 go:generateViper 读写配置文件ZAP 保存日志定时任务创建apimodel步骤 1. 创建service步骤 2. 创建api步骤 3. 创建router 初始化总路由启动go-swagger路由配置swag init test将嵌套结构定义为指针或对象利弊结构体嵌套学习资源 go:generate //go:generate go env -w …...

2023-10-17 mysql-innodb-解析write_row的record的一行数据-分析

摘要: 2023-10-17 mysql-innodb-解析write_row的record的一行数据-分析. record是一行数据的序列化后的一整个字节流, 在innodb中需要解读出字段. 本文分析如何解析record, 以便学习这种技巧. row_mysql_store_col_in_innobase_format 调用堆栈: #0 row_mysql_store_col_in…...

认识web自动化测试!

1.什么是自动化测试&#xff1f; 自动化测试的概念: 软件自动化测试就是通过测试工具或者其他手段&#xff0c;按照测试人员的预定计划对软件产品进行自动化测试&#xff0c;他是软件测试的一个重要组成部分&#xff0c;能够完成许多手工测试无法完成或者难以实现的测试工作&a…...

多商户进驻小程序商城的作用是什么

多商户进驻商城简单来说就是在一个商城里&#xff0c;由经营者邀请同行、异业商家进驻到商城里&#xff08;子商户&#xff09;&#xff0c;可丰富商城经营业态&#xff0c;满足客户多方购物需求&#xff0c;打造购物商圈及经营者获得更多收益等。 通过【雨科】平台的多商户进驻…...

接口响应慢该如何排查

不知道大家有没有遇到这种情况&#xff0c;接口业务逻辑写完后&#xff0c;用 postman 一调&#xff0c;发现接口响应时间好长&#xff0c;不得不对接口进行优化。但是此时接口的代码往往逻辑比较复杂&#xff0c;调用层次也比较多&#xff0c;很难定位到耗时较长的代码块。 遇…...

spring boot MongoDB实战

文章目录 项目搭建文章评论实体类的编写文章评论的基本增删改查根据上级ID查询文章评论的分页列表MongoTemplate实现评论点赞 GITHUB 项目搭建 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0&q…...

企业数字化转型时,会遇到的5大挑战

企业数字化转型时&#xff0c;会遇到的5大挑战添加链接描述 数字化转型已然是当今商业战略的一大基石&#xff0c;根据Gartner的《2023年度董事会调查》显示&#xff0c;有89%的企业将数字业务视为其增长的核心。但该研究的另一项统计数据也显示&#xff1a;在这些企业中&…...

动态语句 sqlserver

EXEC sp_executesql DynamicSQL, NFirstName NVARCHAR(50), LastName NVARCHAR(50), FirstName, LastName在EXEC sp_executesql语句中&#xff0c;后面的参数需要按特定顺序传递。这些参数的顺序如下&#xff1a; 1.第一个参数是动态SQL语句本身&#xff0c;通常是一个NVARCHA…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...