咱们好,我是坤哥

今天给咱们同享两个比较有用的浏览器行为与预期不一致的现象,这两个问题其实并不是什么难题,但在作业中发现不少人被难住了,在我的印象中至javascript是干什么的少有三位伙javascript和java的差异伴在群里问这样的问题,上星期又有同伴被此现象困住了,所以我觉得这Java应该是个共性问题,在这儿同享给咱们,希望对咱们有帮忙,欢迎咱们注重群众java初学号「码海」,共同进步

现象一、点击按钮无法完结文件下载

前端同伴反应在浏览器里appear点击完结好的「下载产chrome手机版品图片」按钮却无法下载(预期应该下载 zip 文appointment件)

这个超时问题难住了我至少三位搭档

但假定你在浏览器的地址栏里输入此下载地址却又能直接从浏览器里下载,这是为何?

咱们能够翻开调试东西「网络部分」,然后点击一下上面chromecast的「下载产品图片」,首要看一下网络央求是否正常。

1、 首要看央求头,能够看出状况码是 200,别的还有 conthttp://www.baidu.coment-disposition 与 Conappointmenttent-Type 这两个 response header
这个超时问题难住了我至少三位搭档

画外音:Content-Type: application/octet-stream 告知客户端这是一个二进制文件,content-disposition 告知客户端这是一个https和http的差异需求下载的附件并告知浏览器该附件默许的文件名。app装置下载

2、再看此央求的 response body,是否和过程一的 applicationjava怎样读/octet-stream 相符:

这个超时问题难住了我至少三位搭档

能够看到 response 便是一堆乱码,即文件的二进制流表现方法,所以从央求来看其实是没有问题的,文件是正常的回来的,但为啥文件却没有下载下来,下载下来的文件去哪里了呢,留神看上图的javascript数据类型另一个红框 **XHR **,它的全称是 XMLHttpRequejava开发工程师st,是 ajax 央求的一种表现方法。

ajax 本身无法触发浏览器的下载功用, 它的java怎样读 response 会交由JavaScript JavaScript 处理,运用 ajax 下载完结后,rjavascriptesponse 以application字符串的方法存储在内存中,那javascript怎样读运用 ahttpclientjax 就无法下载了吗?不是的,咱们看下浏览器为啥能下载

咱们发现运用浏览器的 GET 央求(主要chromecast以 frame 加载, a 标签点击触发)或 POST央求(以 form 的方法存在)是能够下载文件的,由于这是浏览器的内置作业,下载的 response 会交由浏览器自己处理,浏览器假定辨认到是二进制流数据则下载,假定辨认到是能够翻开的文件,如http://192.168.1.1登录 xml, image 等则不会下载,会以预览的款式存在。

那么为啥 ajax 不能默许完结文件下载呢,这是浏览器的安全策略束缚的,试想假定 ajax 能够下载文件,那就意味着 ajax 能够直接与磁盘交互,这会存在严峻的安全隐患。

根据以上剖析,要运用 ajax 下载文件咱们也就有思路了,已然chromebook运用 a 标签(或 frame)的点击作业能够触发浏览器的内置下载行为,那咱们在用 ajax 下载拿到 response 后,能够用 js 新建一个躲藏的 a 标签(标签的 href 指向文件的链接),实施它的 click 作业,这样就触发了浏览器的内置下载作业,就能够下载文件了,不过需求留java面试题心的事,创建的 a 标签中要增加一个 download 特色,如 下载。

这个 download 特色有啥用呢,对于浏览器chrome安卓下载能翻开java开发得文件,例如 htjavascript面试题ml,xmjava开发l 等,假定你不加 download,点击 a 标签就不是下载了,而是翻开,(留神 download 特色现在httpclient只被火狐和谷歌兼容)

运用 ajax 来实施下http 302载文件的代码示例如下:

const filename = response.headers['content-disposition'].match(
/filename=(.*)javascript数据类型/
)[1]
// 首要要创建一个 Blob 目标(表示不可变、原始数据的类文件目标)
const blob = new Blobhttp 500([rapp装置下载esphttpclientonse.data], {type: 'application/zip'});
if (typeof window.navigator.msSaveBlob !== 'undefined') {
// 兼容IE,window.navigapp装置下载ator.msSaveBlobjava面试题:以本地方法保存文件
window.navigator.msSaveBlob(blob, djava初学ecodeURI(filename))
} else {
let elink = document.cchrome什么意思reateElement("a"); // 创建一个javascript怎样读<a>标签
elink.style.display = "nhttp协议one"; // 躲藏标签
elink.href = window.Ujavascript菜鸟教程RL.creachrometeObjectURL(blob); // 配备hrefchrome安卓下载,指向本地文件的内存地址
elink.download = filename;
elink.click();
URhttp://192.168.1.1登录L.revokeObjectURL(elink.href); //javascript 释放app装置下载URL 目标
document.body.removeChild(elink); // 移除&ljavascript高档程序设计t;a>标签
}

现象二、在浏览器输入图片链接想预览,效果却变成了下载图片

这个问题其实经由上文剖析,相信你不难猜出是咋回事,我approach们先抓包看一下:chrome安卓下载

这个超时问题难住了我至少三位搭档

能够看到回来的 Content-Type 为 octet-stream,上文咱们说到,它指任意类型chrome浏览器的二进制流java就业培训班数据,一般下载文件回appreciate来的是这种类型,浏览器由于无法辨认翻开流数据httpclient,所以会下载,那为啥大多数图片在浏览器上是能够预览的呢,由于它回来的 Content-Type 是 image/png 或 image/jpeg 等浏览器能够直接辨认翻javascript:void(0)开的文件,这样就不会实施下载作业

总结

以上两个问题需求咱们对浏览器的作业机制与 HTTP 协议有一定的了解,所以基础真的很重要啊,否则很可能你排查半天也无从下手,但假定你知道了这些原理,抓个包剖析一下它们的 Content-Type,瞬间就茅塞顿开了javascript和java的差异!别的对一些疑难杂症,了解 HTTP 协议与浏览器的作业机制也有助于帮忙你快速定位解approach决问题。

比如上图的解决方案中咱们经过 content-disposition 来获取文件的称谓

conapplest filename = response.headjavascripters['content-disposition'].match(
/filename=(.*)/
)[1]

但在最开端发现这段代码有问题,打印日chrome直接下载志发现 response.headers[‘content-disposition’] 竟然为空,但是翻开浏览器的 network 会发现, content-dispoJavasition 清楚存在啊

这个超时问题难住了我至少三位搭档

那为啥在 reponse 的 header 里拿不到 content-disposition 呢?

一查发现本来仍是 HTTP 协议的问题

默许情况下,header 只有七种 simple response headers (简略照顾首部)能够显露给外部:

Cache-Control
Content-HTTPLanguagehttps和http的差异
Content-Length
Content-Type
Expires
Last-Modified
Pragma

这儿的显露给外部,意思是让客户端(比如 Chrchrome浏览器ome)能够访问得到,既能够在 Network 里看到,也能够在代码里获取到他们的值。

而 content-disposition 不在其间,所以即便服务器在协议回包里加了该字段,如下

response.setHeader("content-disposition", "attachment; filename=" + fihttps和http的差异lename);

但因没“显露”给外部,客户端就「httpwatch看得到,吃不到」。

app装置下载照顾首部 Access-Conjavascript什么意思trol-Expose-Headers 便是控制“显露”的开关appointment,它列出chrome浏览器了哪些首部能够作为照顾的一部分显javascript露给外部。

所以假定想要让客户端能够访问到JavaScript其他的首部信息,服务器不仅要在 header 里参加该首部,还要将它们在 Access-Cappearontrol-Expose-Hjava语言eaders 里面列出来,如下:

response.setHeader("Access-Controlhttpclient-Expose-Headers", "Content-Disposition");
response.setHeader("content-disposition", "attachment; filename=" + filename);

这样的话 JS 的 response header 里就有 conteJavant-disposchrome手机版ition 的值啦。

参看链接:
Access-Control-Exposejava就业培训班-Headers: 1il58.cn/AptUz