小发现: window.open() 和 飞书网页api 预览文件

本文描述了在iOS设备上使用uniapp和飞书API预览PDF文件时遇到的兼容性问题,特别是iPhone 7和8机型。作者通过调整代码,避免使用飞书的预览功能,改为使用`window.open()`直接打开新窗口来解决预览问题。在某些情况下,由于异步请求导致预览失败,作者改为页面加载时预先获取URL并存储在data中,确保用户点击时能立即预览。此外,文章还提供了一个参考链接以供进一步研究。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业务场景:
在ios手机去预览pdf文件,本身该项目是基于uniapp开发的h5页面,使用了飞书的网页式鉴权,飞书的api方法内自带预览文件功能,本来我使用的是风生水起;

在这里插入图片描述

奈何,测试提出的了一个bug,在" ios系统 " 苹果p7、p8 手机预览时,没有反应,也没有报错,Σσ(・Д・;)我我我什么都没做!!!,哎哎哎哎哎 ,挠头挠头~

既然这个方法无法解决,此时又没有时间能让我去研究它究竟是为什么,我只能另辟蹊径;就不借助飞书自带的api去实现了,直接新打开窗口使用 window.open(),同时测试反映安卓手机没有问题,那我就只处理ios系统,真是机智如我!┗( ▔, ▔ )┛
在这里插入图片描述
好家伙,还有问题,好几个页面用得都是这个方法,其他都好好的,但偏偏其中一个按钮点击还是在ios手机就是没反应,主要问题是没有报错o((⊙﹏⊙))o ,,,,,,

左思右想到底是为啥啊,就开始查找上下文,对比其他成功的页面到底是什么影响到了,后发现,单单这个有问题的window.open(),前执行了个异步请求接口;后把接口注释,直接打开新窗口,发现是可行的,难道真的是异步的问题???????
在这里插入图片描述
既然如此那我就进入页面的时候直接请求获取这个链接存到data里,再在用户点击的时候按钮时,判断data里值的长度,进行操作,发现是可行的,皆大欢喜(σ゚∀゚)σ…:*☆哎哟不错哦;

data() {
	return {
		contractFileUrl: ''
	}
},
methods: {
	async showContaractPdf() {
		if (this.contractFileUrl !== '') {
			await uni.showLoading({
				mask: true,
			  title: '加载中'
			})
			await showFile(this.contractFileUrl)
		} else {
			await uni.showToast({
				title: '请联系管理员添加预览文件',
				icon: "error",
				duration: 2000,
			})
		}
	},
},
async created() {
	await getTemplateSample().then(async res => {
		const { code, data } = res
		this.contractFileUrl = code == 200 ? data.url : ''
	})
}

该方法同时使用了飞书客户端网页应用api,如果不需要删除就好

// 预览文件 该方法同时使用了飞书客户端网页应用api,如果不需要删除就好
export async function showFile(url) {
	console.log('预览附件')
	if (!window.h5sdk) {
		console.log('window.h5sdk 找不到!!!!')
		await uni.hideLoading()
		return false
	}
	var u = navigator.userAgent
	if(u.indexOf('iPhone') > -1) { // ios手机
		window.open(url)
	} else { // 安卓手机
		window.h5sdk.ready(() =>  {
			console.log('走进来了啦')
			const task = tt.downloadFile({ // 先下载到本地,只是临时的文件
			  url,
			  success: async (res) => {
				console.log('downloadFile   成功')
				await tt.openDocument({ // 打开文件
				  filePath: res.tempFilePath,
				  showMenu: true,
				  ...normalCallbacks('toast', 'openDocument')
				})
				await uni.hideLoading()
			  },
			  fail: async (err) => {
				console.log('downloadFile   失败', err)
				await uni.hideLoading()
			  }
			});
			task.onProgressUpdate(res => {
			  console.log(`下载进度为${res.progress, this, Vue}%;`)
			})
		})
	}
}

后发现有个别的博客使用的别的方法实现的,值得参考哦: https://blog.csdn.net/weixin_34406061/article/details/91460923

<think>嗯,用户的问题是关于在JavaScript中使用window.open()时如何携带自定义请求头。我之前看过一些相关的引用资料,现在需要整理一下思路。 首先,根据引用[1],使用iframe、window.open或者a标签打开新页面时,无法直接设置请求头,所以需要其他方法。引用[2]提到用window.open直接请求后台接口,但可能没有处理请求头。引用[3]中的例子使用axios发送带有自定义头的请求,获取数据后通过URL.createObjectURL打开新窗口,这可能是一个解决方案。 那用户的需求是携带自定义headers,而直接使用window.open无法做到,因为浏览器的安全限制不允许修改请求头。所以需要间接的方法,比如先通过AJAX或fetch发送带有自定义头的请求,获取数据后再用window.open展示。 例如,引用[3]中的代码用axios获取PDF文件,设置responseType为blob,然后生成URL并用window.open打开。这可能适用于需要预览文件的情况。如果是其他类型的数据,可能需要不同的处理方式,比如创建隐藏表单或者使用post请求,但表单只能设置Content-Type,不能自定义其他头。 另外,服务端配合可能也是一个方向,比如在URL中添加token参数,但这可能不如请求头安全。需要权衡安全性实现难度。 总结下来,可行的方案包括使用AJAX/fetch预先获取数据并处理,或者让服务端支持通过URL参数传递必要的信息。需要根据具体情况选择合适的方法,并注意跨域问题浏览器安全策略的限制。</think>在使用JavaScript的`window.open()`时,浏览器出于安全考虑**不允许直接添加自定义请求头**,但可以通过以下两种方法间接实现类似效果: --- ### 方法一:通过AJAX预先携带请求头获取数据 1. **使用`fetch`或`axios`发送带有自定义头的请求** 通过异步请求获取数据后,将结果转为Blob对象并生成临时URL: ```javascript // 示例:获取PDF文件预览 fetch('https://api.example.com/data', { method: 'GET', headers: { 'Authorization': 'Bearer your_token', 'Custom-Header': 'value' } }) .then(response => response.blob()) .then(blob => { const url = window.URL.createObjectURL(blob); window.open(url, '_blank'); // 新窗口展示内容 window.URL.revokeObjectURL(url); // 释放内存 }); ``` 此方法适用于**文件预览或数据展示**场景[^3]。 2. **限制** - 需要处理跨域问题(服务端需配置CORS); - 仅适用于GET请求,且无法直接控制新窗口的URL显示。 --- ### 方法二:通过URL参数传递关键信息 1. **将Token或标识拼接在URL中** 如果自定义头用于身份验证(如Token),可将其作为URL参数传递: ```javascript window.open(`https://api.example.com/data?token=${your_token}`); ``` 服务端需接收并处理该参数[^2]。 2. **限制** - URL参数可能被浏览器历史记录或日志记录,存在安全风险; - 无法传递敏感信息(建议配合HTTPS使用)。 --- ### 替代方案:使用隐藏表单(仅限POST请求) ```javascript // 动态创建表单并提交 const form = document.createElement('form'); form.method = 'POST'; form.action = 'https://api.example.com/data'; form.target = '_blank'; // 新窗口打开 const tokenInput = document.createElement('input'); tokenInput.type = 'hidden'; tokenInput.name = 'token'; tokenInput.value = 'your_token'; form.appendChild(tokenInput); document.body.appendChild(form); form.submit(); document.body.removeChild(form); ``` 此方法支持POST请求,但**无法设置任意请求头**,只能通过表单字段传递数据。 --- ### 总结 | 方法 | 适用场景 | 安全性 | 灵活性 | |--------------------|----------------------------|--------|----------------| | AJAX + Blob | 文件预览、数据展示 | 高 | 高(需CORS) | | URL参数 | 简单身份验证、非敏感数据 | 中 | 低 | | 隐藏表单 | POST请求传递数据 | 中 | 中 | **推荐优先使用AJAX+Blob方案**,并在服务端配置CORS响应头(如`Access-Control-Allow-Headers`)以支持自定义头[^1]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值