基于 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;
- }
- }
基于 Nginx XSendfile + SpringMVC 进行文件下载的更多相关文章
- 【转载】【JAVA秒会技术之图片上传】基于Nginx及FastDFS,完成图片的上传及展示
基于Nginx及FastDFS,完成商品图片的上传及展示 一.传统图片存储及展示方式 存在问题: 1)大并发量上传访问图片时,需要对web应用做负载均衡,但是会存在图片共享问题 2)web应用服务器的 ...
- 基于Nginx dyups模块的站点动态上下线并实现简单服务治理
简介 今天主要讨论一下,对于分布式服务,站点如何平滑的上下线问题. 分布式服务 在分布式服务下,我们会用nginx做负载均衡, 业务站点访问某服务站点的时候, 统一走nginx, 然后nginx根据一 ...
- 基于nginx tomcat redis分布式web应用的session共享配置
一.前言 nginx 作为目前最流行的开源反向代理HTTP Server,用于实现资源缓存.web server负载均衡等功能,由于其轻量级.高性能.高可靠等特点在互联网项目中有着非常普遍的应用,相关 ...
- 基于nginx的tomcat负载均衡和集群
要集群tomcat主要是解决SESSION共享的问题,因此我利用memcached来保存session,多台TOMCAT服务器即可共享SESSION了. 你可以自己写tomcat的扩展来保存SESSI ...
- 转: 基于nginx的hls直播系统
转自:http://blog.csdn.net/cjsafty/article/details/9108587 看点: 1. 详细解解答了 nginx rtmp配置过程. 前写了一篇基于nginx的h ...
- Windows 环境下基于 nginx 的本地 PyPI 源
Windows 环境下基于 nginx 的本地 PyPI 源的搭建: 1.登录 nginx 官网,下载安装包
- 7个基于Linux命令行的文件下载和网站浏览工具
7个基于Linux命令行的文件下载和网站浏览工具 时间:2015-06-01 09:36来源:linux.cn 编辑:linux.cn 点击: 2282 次 Linux命令行是GNU/Linux中最神 ...
- 基于nginx+lua+redis高性能api应用实践
基于nginx+lua+redis高性能api应用实践 前言 比较传统的服务端程序(PHP.FAST CGI等),大多都是通过每产生一个请求,都会有一个进程与之相对应,请求处理完毕后相关进程自动释放. ...
- Ubuntu 14.10下基于Nginx搭建mp4/flv流媒体服务器(可随意拖动)并支持RTMP/HLS协议(含转码工具)
Ubuntu 14.10下基于Nginx搭建mp4/flv流媒体服务器(可随意拖动)并支持RTMP/HLS协议(含转码工具) 最近因为项目关系,收朋友之托,想制作秀场网站,但是因为之前一直没有涉及到这 ...
随机推荐
- [React Storybook] Get started with Storybook for React
Storybook is a UI component development environment for React, Vue, and Angular. With that, you can ...
- LinkedList,ArrayList末尾插入谁效率高?
废话不多说,原因不解释.上測试代码: package com.letv.cloud.cdn.jtest; import java.io.IOException; import java.util.Ar ...
- 启动VIP报CRS-1028/CRS-0223致使VIP状态为UNKNOWN故障分析与解决
CRS版本号为10.2.0.4 1.VIP State为UNKNOWN [root@XXdb1 ~]# crs_stat -t Name Type Target ...
- 文字过长 用 ... 表示 CSS实现单行、多行文本溢出显示省略号
单行文本溢出显示省略号 max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; 多行文本 ...
- centos vi和vim用法
所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主动的以字体颜色辨别语法的正 ...
- Django day05 视图层之 (HttpRequest) \ (HttpResponse) \ (JsonResponse) 对象
一:视图层之HttpRequest对象 # 前台Post传过来的数据,包装到POST字典中 # request.POST # 前台浏览器窗口里携带的数据,包装到GET字典中 # request.GET ...
- POJ 3230 DP
f[i][j]=max(f[i][j],f[i-1][k]-a[k][j]+b[i][j]) i->第i天 j-–>到第j个城市 #include <cstdio> #incl ...
- CDH版Phoenix的安装(图文详解)
不多说,直接上干货! 写在前面的话 我这里,四个节点的bigdata集群.分别为cmbigdata1.cmbigdata2.cmbigdata3和cmbigdata4. https://i.cnblo ...
- WPF TextBox 仅允许输入数字
因为在 IValueConverter 实现中,当文本不能转换为目标类型时返回 DependencyProperty.UnsetValue ,Validation.GetHasError 返回 tru ...
- PHP中的魔术方法和魔术常量
看上去好像挺烦人,但只要通过例子测试一下,就明白了.不做测试,只是看,第二天还是不明白.当然我在抄其他人的日志,然后希望能是自己的理解就好,原文地址PHP的魔术方法和魔术敞亮简介和使用--LaraBo ...