基于 Nginx XSendfile + SpringMVC 进行文件下载
转自:http://denger.iteye.com/blog/1014066
基于 Nginx XSendfile + SpringMVC 进行文件下载
PS:经过实际测试,通过 nginx 提供文件下载功能的时候,在 Application Server(Java/RoR/Go...) 端不设置 Content-Length 也是可以的
在平常我们实现文件下载通常是通过普通 read-write方式,如下代码所示。
- @RequestMapping("/courseware/{id}")
- public void download(@PathVariable("id") String courseID, HttpServletResponse response) throws Exception {
- ResourceFile file = coursewareService.downCoursewareFile(courseID);
- response.setContentType(file.getType());
- response.setContentLength(file.contentLength());
- response.setHeader("Content-Disposition","attachment; filename=\"" + file.getFilename() +"\"");
- //Reade File - > Write To response
- FileCopyUtils.copy(file.getFile(), response.getOutputStream());
- }
由于程序的IO都是调用系统底层IO进行文件操作,于是这种方式在read和write时系统都会进行两次内存拷贝(共四次)。linux 中引入的 sendfile 的实际就为了更好的解决这个问题,从而实现"零拷贝",大大提升文件下载速度。
使用 sendfile() 提升网络文件发送性能
RoR网站如何利用lighttpd的X-sendfile功能提升文件下载性能
在apache,nginx,lighttpd等web服务器当中,都有sendfile feature。下面就对 nginx 上的XSendfile与SpringMVC文件下载及访问控制进行说明。我们这里的大体流程为:
1.用户发起下载课件请求; (http://dl.mydomain.com/download/courseware/1)
2.nginx截获到该(dl.mydomain.com)域名的请求;
3.将其proxy_pass至应用服务器;
4.应用服务器根据课件id获取文件存储路径等其它一些业务逻辑(如增加下载次数等);
5.如果允许下载,则应用服务器通过setHeader -> X-Accel-Redirect 将需要下载的文件转发至nginx中);
6.Nginx获取到header以sendfile方式从NFS读取文件并进行下载。
其nginx中的配置为:
在location中加入以下配置
- server {
- listen 80;
- server_name dl.mydomain.com;
- location / {
- proxy_pass http://127.0.0.1:8080/; #首先pass到应用服务器
- proxy_redirect off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- client_max_body_size 10m;
- client_body_buffer_size 128k;
- proxy_connect_timeout 90;
- proxy_send_timeout 90;
- proxy_read_timeout 90;
- proxy_buffer_size 4k;
- proxy_buffers 4 32k;
- proxy_busy_buffers_size 64k;
- proxy_temp_file_write_size 64k;
- }
- location /course/ {
- charset utf-8;
- alias /nfs/files/; #文件的根目录(允许使用本地磁盘,NFS,NAS,NBD等)
- internal;
- }
- }
其Spring代码为:
- package com.xxxx.portal.web;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.PathVariable;
- import org.springframework.web.bind.annotation.RequestMapping;
- import com.xxxx.core.io.ResourceFile;
- import com.xxxx.portal.services.CoursewareService;
- /**
- * File download controller, provide courseware download or other files. <br>
- * <br>
- * <i> download a course URL e.g:<br>
- * http://dl.mydomain.com/download/courseware/1 </i>
- *
- * @author denger
- */
- @Controller
- @RequestMapping("/download/*")
- public class DownloadController {
- private CoursewareService coursewareService;
- protected static final String DEFAULT_FILE_ENCODING = "ISO-8859-1";
- /**
- * Under the courseware id to download the file.
- *
- * @param courseID The course id.
- * @throws IOException
- */
- @RequestMapping("/courseware/{id}")
- public void downCourseware(@PathVariable("id") String courseID, final HttpServletResponse response) throws IOException {
- ResourceFile file = coursewareService.downCoursewareFile(courseID);
- if (file != null && file.exists()){
- // redirect file to x-accel-Redirect
- xAccelRedirectFile(file, response);
- } else { // If not found resource file, send the 404 code
- response.sendError(404);
- }
- }
- protected void xAccelRedirectFile(ResourceFile file, HttpServletResponse response)
- throws IOException {
- String encoding = response.getCharacterEncoding();
- response.setHeader("Content-Type", "application/octet-stream");
- //这里获取到文件的相对路径。其中 /course/ 为虚拟路径,主要用于nginx中进行拦截包含了/course/ 的URL, 并进行文件下载。
- //在以上nginx配置的第二个location 中同样也设置了 /course/,实际的文件下载路径并不会包含 /course/
- //当然,如果希望包含的话可以将以上的 alias 改为 root 即可。
- response.setHeader("X-Accel-Redirect", "/course/"
- + toPathEncoding(encoding, file.getRelativePath()));
- response.setHeader("X-Accel-Charset", "utf-8");
- response.setHeader("Content-Disposition", "attachment; filename="
- + toPathEncoding(encoding, file.getFilename()));
- // response.setContentLength((int) file.contentLength()); // 经过实际测试,这里不设置 Content-Length 也是可以的
- }
- //如果存在中文文件名或中文路径需要对其进行编码成 iSO-8859-1
- //否则会导致 nginx无法找到文件及弹出的文件下载框也会乱码
- private String toPathEncoding(String origEncoding, String fileName) throws UnsupportedEncodingException{
- return new String(fileName.getBytes(origEncoding), DEFAULT_FILE_ENCODING);
- }
- @Autowired
- public void setCoursewareService(CoursewareService coursewareService) {
- this.coursewareService = coursewareService;
- }
- }
转载于:https://www.cnblogs.com/leonxyzh/p/7288991.html
基于 Nginx XSendfile + SpringMVC 进行文件下载相关推荐
- 直播系统开发:基于Nginx与Nginx-rtmp-module PDF文件下载
本博客做为实践补充. 大纲就不写了,首先,书偏应用,适合新手! 直播系统开发:基于Nginx与Nginx-rtmp-module下载地址 https://download.csdn.n ...
- Apache,Nginx,Lighttpd分别使用X-sendfile功能提升文件下载性能
关于mod_xsendfile https://tn123.org/mod_xsendfile/ Lighttpd中的X-sendfile RoR网站如何利用lighttpd的X-sendfile功能 ...
- 基于nginx的tomcat负载均衡和集群(超简单)
今天看到"基于apache的tomcat负载均衡和集群配置 "这篇文章成为javaEye热点. 略看了一下,感觉太复杂,要配置的东西太多,因此在这里写出一种更简洁的方法. 要集群t ...
- 基于nginx实现反向代理
准备工作:关闭虚拟机防火墙,selinux,关闭物理机防火墙,关闭物理机的代理. 第一步:配置上游服务器(这里用apache) 1.安装apache # yum install httpd -y 2. ...
- nginx rtmp 编码_基于Nginx的媒体服务器技术
国内应用比较多的开源流媒体服务器nginx-rtmp-module一直存在功能少.集群化难度大等问题.在LiveVideoStack线上分享中,PingOS 开源项目组开发工程师.UCloud RTC ...
- 【多线程编程学习】java多线程基于数据分割的大文件下载器
文章目录 代码:基于数据分割的大文件下载器 作为包装的存储对象类: 主文件下载类: 子任务下载类: 处理缓存: 启动类: 数据分割思想产生的问题 代码来自书籍<java多线程编程实战指南> ...
- 基于Nginx的媒体服务器技术
国内应用比较多的开源流媒体服务器nginx-rtmp-module一直存在功能少.集群化难度大等问题.在LiveVideoStack线上分享中,PingOS 开源项目组开发工程师.UCloud RTC ...
- Upsync:微博开源基于Nginx容器动态流量管理方案
编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由姚四芳在高可用架构群分享.转载请注明来自高可用架构公众号「 ArchNotes 」. 姚四芳,新浪微博高级技术专家,微博平台架构组技术负 ...
- ts获取服务器数据_基于Nginx的媒体服务器技术-线上公开课
国内应用比较多的开源流媒体服务器nginx-rtmp-module一直存在功能少.集群化难度大等问题.在LiveVideoStack线上分享中,PingOS 开源项目组开发工程师.UCloud RTC ...
最新文章
- 还在头秃自己的转录组数据怎么处理画图发文章,不如来看看这个
- ubuntu更改用户名密码
- 改变Android的hello world程序字体颜色和背景颜色
- .NET 实现并行的几种方式(二)
- 1799元起!66W超级快充+120Hz全视屏 荣耀Play5 活力版正式发布
- compilation error错误是什么原因_了解如何使用Try,Throw,Catch和Last处理JavaScript错误...
- SEO:提高关键词排名的28个SEO技巧
- 学习3ds max插件开发过程中的一些小结
- 用python处理txt文件
- 荷兰国旗问题(C语言)
- linux网络测速qerf,www.cpg.com.ph
- 计算机验证iq oq pq,验证、确认、鉴定过程、DQ、IQ、OQ、PQ这几个概念如何理解?...
- n个人有c个魔法帽几天去掉所有的帽子
- 跑跑卡丁车手游怎么用电脑玩 跑跑卡丁车模拟器玩法教程
- gprs数据传输流程
- 初探强化学习(2)rollout算法
- 公众平台 php,微信公众平台PHP开发
- flutter 如何实现虚线框按钮
- 《数学建模简明教程--基于python》学习笔记-第四章-微分方程-课后习题解答
- 那些坚持买彩票想中500万的人,都是一些什么心态?分析一下
热门文章
- 对OS实验中的“管道”的一点儿理解
- 你是AI王者吗?2018人工智能专业期末考试,66666奖学金等你来
- cmd系统命令不识别
- A+B Problem 详细解答 (转载)
- No_16_0303 Java基础学习第十一天
- 【神奇的函数式编程语言的独特功能】Lisp 的运行期修改、编译代码,并替换当前运行版本的试验...
- linux命令使用全集
- [常见错误]Python.h: No such file or directory
- 不聋不哑,不做当家之解
- python执行外部命令或URL