http mime type
content-type 支持的 media types:www.iana.org/assignments…
后端发给的 mime type
后端一顿操作后,设置一堆响应头
然后我们去调用接口,如果需要下载的话,后端会调用流输出方法
response.getOutputStream()
axios responseType 类型的设置
responseType 表示浏览器将要响应的数据类型
其中 blob,arraybuffer 用于 excel,pdf 这种数据流文件下载
打不开文件相关问题
后端返回数据流 excel,pdf 下载之后,打不开问题
- 有可能是编码不对
- 接口没加上 responseType 响应类型,指定浏览器响应的类型
- 本地开启了mockjs,相应类型也可能会受到影响,mockjs会影响原生的 ajax 请求,使得服务器返回的 blob/arraybuffer 类型的变成乱码
// 1. 处理返回数据流下载过程编码不对
export const useDownloadFile = (data: Blob, fileName: string, format: string) => {
let name!: string
let type = ''
if (format === 'pdf') {
// 这里的 type 类型要与 接口响应头的 content-type 保持一致
type = 'application/pdf;chartset=utf-8'
name = `${fileName}.pdf`
}
if (format === 'excel') {
// 这里的 type 类型要与 接口响应头的 content-type 不一致,缺少 utf-8 编码
type = 'application/vnd.ms-excel;'
name = `${fileName}.xlsx`
}
const blob = new Blob([data], { type: type })
/**省略下载处理过程**/
}
// 2. 第二种情况,接口没加响应类型
export const $DownloadPartList = (params: IDownloadPartListParams): Promise<Blob> => {
return $axios.post(`xxxx`, params)
}
// 3. 可能本地开启了 mockjs,会有影响,暂时没用
这三种情况都有可能导致下载的 excel,pdf打不开
正确是方式:
// 1. 处理返回数据流下载过程 type 类型要与 接口响应头的 content-type 保持一致
export const useDownloadFile = (data: Blob, fileName: string, format: string) => {
let name!: string
let type = ''
if (format === 'pdf') {
// 这里的 type 类型要与 接口响应头的 content-type 保持一致
type = 'application/pdf;chartset=utf-8'
name = `${fileName}.pdf`
}
if (format === 'excel') {
// 这里的 type 类型要与 接口响应头的 content-type 保持一致
type = 'application/vnd.ms-excel;chartset=utf-8'
name = `${fileName}.xlsx`
}
const blob = new Blob([data], { type: type })
/**省略下载处理过程**/
}
// 2. 第二种情况,接口加响应类型
export const $DownloadPartList = (params: IDownloadPartListParams): Promise<Blob> => {
return $axios.post(`xxx`, { ...params }, { responseType: 'arraybuffer' })
}
// 3. 关闭 mockjs
不得不说 content-type 和 content-disposition,X-Content-Type-Option
content-type:在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。 浏览器会在某些情况下进行MIME查找,并不一定遵循此标题的值;
// pdf
content-type: application/pdf;chartset=utf-8
// excel
content-type: application/vnd.ms-excel;charset=utf-8
// json
content-type: application/json
// multipart form data boundary 表示分隔符,这种可以分段传输
content-Type: multipart/form-data; boundary=----WebKitFormBoundaryVHUV1SACt6dkGtj9
x-content-type-option:为了防止不遵循content-type,可以将标题X-Content-Type-Options设置为nosniff。这个就是跟excel,pdf下载的时候出现打不开的情况息息相关,表示前端处理数据流下载的类型要跟content-type一致content-disposition:当文件支持下载的情况,就会设置这个字段,其中attachment表示支持下载
Content-Disposition: inline // 直接在页面打开
Content-Disposition: attachment // 支持下载
Content-Disposition: attachment; filename="filename.jpg"
// form-data形式
Content-Disposition: form-data
Content-Disposition: form-data; name="fieldName"
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"
回到上面下载 excel,pdf 的例子
content-type 为 multipart/form-data; boundary=*** 的情况
浏览器识别到这种 form-data 格式的接口,会自动设置 multipart/form-data; boundary=----WebKitFormBoundaryyUZoKpRYHZjSBBTP
看这篇文章的解析:juejin.cn/post/697106…
浏览器会解析成这样
- 起始分隔符:
------multipart/form-data; boundary=----WebKitFormBoundaryyUZoKpRYHZjSBBT - 字段:
Content-Disposition: form-data; name="billno" - 空行
- 再是对应的值:
FBBJD20221219401263 - 结束分隔符:
------multipart/form-data; boundary=----WebKitFormBoundaryyUZoKpRYHZjSBBT和--
前端API处理流
- 不可变二进制字节流:blob
- 针对文件字节流blob不可变升级版本:fileReader 像上传图片,前端图片预览
- 可变二进制字节流:arraybuffer
响应类型是 arraybuffer 有两种处理方式
- 一种是直接使用
blob对象处理 - 另一种就是先写入
arraybuffer缓冲区,然后操作 arraybuffer - 一般都是选择第一种方式
参考链接:blog.csdn.net/weixin_4329…
更多 arraybuffer, fileReader, 其他对象使用,后面使用到再补充
// 将返回的数据用数组包起来,为 `Blob` 对象创建一个 类型化数组,然后使用 `URL.createObjectURL(blob)` 转成一个链接进行下载
// 这里的 `type` 也是对应 `content-type` 里面的 `mime type` 类型
export const useDownloadFile = (data: Blob, fileName: string, format: string) => {
let name!: string
let type = ''
if (format === 'pdf') {
type = 'application/pdf;chartset=utf-8'
name = `${fileName}.pdf`
}
if (format === 'excel') {
type = 'application/vnd.ms-excel;charset=utf-8'
name = `${fileName}.xlsx`
}
// [data] 为 Blob 对象创建一个 类型化数组,这里的 type 与 content-type 保持一致
const blob = new Blob([data], { type: type })
if ('download' in document.createElement('a')) {
// 非IE下载
const elink = document.createElement('a')
elink.download = name
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
document.body.removeChild(elink)
} else {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(window.navigator as any).msSaveBlob(blob, name)
} catch (e) {
console.log(e)
}
}
}
http 安全
-
X-Content-Type-Options:消息头相当于一个提示标志,被服务器用来提示客户端一定要遵循在
Content-Type首部中对 MIME 类型 的设定,而不能对其进行修改 -
X-Frame-Options:如果设置为
DENY,不光在别人的网站 frame 嵌入时会无法加载,在同域名页面中同样会无法加载。另一方面,如果设置为SAMEORIGIN,那么页面就可以在同域名页面的 frame 中嵌套。 -
X-XSS-Protection:
X-XSS-Protection: 0 禁止 XSS 过滤。 X-XSS-Protection: 1 启用 XSS 过滤(通常浏览器是默认的)。如果检测到跨站脚本攻击,浏览器将清除页面(删除不安全的部分)。 X-XSS-Protection: 1; mode=block 启用 XSS 过滤。如果检测到攻击,浏览器将不会清除页面,而是阻止页面加载。 X-XSS-Protection: 1; report=<reporting-uri> 启用 XSS 过滤。如果检测到跨站脚本攻击,浏览器将清除页面并使用 CSP report-uri (en-US)指令的功能发送违规报告。