浏览 5260 次
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-04-24
最后修改:2011-04-25
@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()); } //如果存在中文文件名或中文路径需要对其进行编码成 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; } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-05-10
呵呵楼主写的不错,bbossgroups项目的mvc框架也很容就可以实现类似的功能,不防一试,而且提供现成的demo,下载地址为:
http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-war.zip/download 源码下载地址为: http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/bbossgroups-3.1-src.zip/download 简单的eclipse开发工程下载地址为: http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/mvcdemo-eclipse.zip/download 培训ppt的下载地址为: http://sourceforge.net/projects/bboss/files/bbossgroups-3.1/bbossgroups%203.1%20in%20action.zip/download |
|
返回顶楼 | |