1、浏览器通过url请求资源的原理和实质,我们先看一个url地址。
http://localhost/download.php?Content-Dispositon=attachment(以下简称url1)
我们以php为例解释下在web浏览器输入这个地址后服务器上的apache服务器是怎么运作的。
首先,浏览器设计的初衷就是请求资源,url的意思就是统一资源定位器。
url1 就是请求localhost(指本地ip,即127.0.0.1)主机上的80端口(url1没有写端口,即默认的80端口)提供的服务下根目录下的download.php文件。
这就是http请求的实质,又因为apache服务器通过cgi接口提供了php解析服务,所以请求download.php等以php为后缀的文件时,服务器不会直接把文件发给客户端,而是经过php解析服务后把相关文件发给客户端。
如果有开发经验的读者,可能对此比较清楚,解析php文件后通常会返回html页面从而让客户端浏览器解析执行,从而显示我们看到的内容。
例如 http://localhost/a.jpg (以下简称url2)
这个url,只要有apache等web服务即可通过在浏览器输入该url,则服务器端就会把该图片发送给客户端浏览器。
经测试,在浏览器输入url2时,浏览器会直接把该图片显示出来。可能有些时候,我们需要的是下载该图片而不是让浏览器直接显示。
所以接下来我们要详细了解下浏览器对服务器返回的资源是怎么处理的?
2、浏览器处理服务器返回资源的处理方式和原理
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,具体的解释大家可自行百度。简单的说就是服务器返回给客户端浏览器资源时,同时会返回response-header,即响应头,响应头里有很多键值对,主要告诉客户端浏览器返回资源的mime类型,内容长度等等。客户端浏览器可以根据mime类型来选择相应的应用程序(或者浏览器插件)来打开服务端返回的资源。
例如 url2请求的是jpg图片,服务器端返回的response-header中content-type为image/jpeg,这样浏览器就知道返回的资源是一张图片,就用浏览器中的打开图片的插件来显示。
(具体的mime类型定义关系 见apache安装目录下的conf/mime.types。)所以,浏览器会根据content-type来处理服务端返回资源的打开方式。如果是zip后缀的压缩文件,浏览器则是弹出下载框让我们选择保存位置。
了解了原理后,我们怎么改变浏览器对资源的默认处理呢?如url2请求的图片我们需要让浏览器弹出下载框而不是直接显示呢?
这里要用到 response-header里的header("Content-Disposition: attachment; filename=" . urldecode($newName));
content-Dispositong值为attachement时,即告诉浏览器,这个资源需要下载而不是用相应的程序打开。
content-Dispositong值不设置的话默认为inline,告诉浏览器在内部打开该资源。
下面以php为例,实现根据url参数来确定是直接显示还是下载。
$contentDisposition="Content-Disposition";
$contenttype="image/jpeg";
$fileurl="old.jpg";
$newName="new.jpg";
header("Content-type:$contenttype"); //设置要下载的文件类型
header("Content-Length:" . filesize($fileurl)); //设置要下载文件的文件大小
header("Content-Disposition:$contentDisposition; filename=" . urldecode($newName)); //设置要下载文件的文件名
readfile($fileurl);
exit();
简单解释下代码,首先获得url1中的查询参数Content-Disposition的值,设置contenttype的值(jpg的值为image、jpeg),$fileurl为资源图片相对于downlload.php的相对路径,$newName为下载框里图片的保存名称,不设置的话默认为图片的原名称;接下来的header函数是设置response-header,分别设置content-type类型,资源的长度以及资源的处理方式和下载时保存到名称。readfile是php内置的读取文件的函数,不了解的可以百度。这样就可以根据url1中Content-Disposition参数的值来确定请求的图片是下载还是直接显示了。
当Content-Disposition=attachement时,下载图片;
当Content-Disposition=inline时,直接在浏览器内打开该图片。
3、另外,简单附上java springmvc框架的源码
@ResponseBody
@RequestMapping(value = "/download",produces="image/jpeg")
public byte[] downloadFile(HttpServletRequest request, HttpServletResponse response,String contentType2,String downloadType)
throws IOException {
byte[]bytes=FileUtils.getBytes4File("D:\\Temp\\cc.jpg");
response.addHeader("Content-Disposition", downloadType+";filename=\"a.jpg\"");
return bytes;
}
各种编程语言的处理原理都是改变response-header,只要理解了http请求资源的原理,也就一会百会了。
我的博客是我学习过程中小成果的速记,有不严谨或错误的地方,希望大家指出,共同进步。