File download based on Nginx XSendfile+SpringMVC

源:http://abear.iteye.com/blog/1025942
评:
Java代码
@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()); 
}


   @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());
    }
    Since the IO of the program calls the underlying IO of the system to perform file operations, in this way, the system will perform two memory copies (four times in total) during read and write. The sendfile introduced in linux is actually to better solve this problem, so as to achieve "zero copy" and greatly improve the file download speed.
    Using sendfile() to improve network file sending performance
    How does RoR website use lighttpd's X-sendfile function to improve file download performance
 

    In web servers such as apache, nginx, and lighttpd, there are sendfile features. The following describes the download and access control of XSendfile and SpringMVC files on nginx. Our general process here is:
     1. The user initiates a request to download the courseware; (http://dl.mydomain.com/download/courseware/1)
     2. nginx intercepts the request to the (dl.mydomain.com) domain name;
     3 .Pass its proxy_pass to the application server;
     4. The application server obtains some other business logic such as the file storage path according to the courseware id (such as increasing the number of downloads, etc.);
     5. If the download is allowed, the application server passes setHeader -> X-Accel-Redirect Forward the file to be downloaded to nginx);
     6. Nginx gets the header and reads the file from NFS in sendfile mode and downloads it.

     The configuration in nginx is:
     add the following configuration
      Conf code to 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/; #The root directory of the file (allows the use of local disk, NFS, NAS, NBD, etc.) 
            internal; 
        } 
    }

server {
        listen 80;
        server_name dl .mydomain.com;

        location / {
            proxy_pass http://127.0.0.1:8080/; #First pass to the application server
            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; Directory (allows to use local disk, NFS, NAS, NBD, etc.)             internal;         }     }     Its Spring code is:     Java code












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"); 
        //The relative path to the file is obtained here. Among them, /course/ is a virtual path, which is mainly used in nginx to intercept URLs containing /course/ and download files. 
        ///course/ is also set in the second location of the above nginx configuration, the actual file download path does not include /course/ 
        //Of course, if you want to include it, you can change the above alias to 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()); 




    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; 
    } 
}

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");
        ​​//The relative path of the file is obtained here. Among them, /course/ is a virtual path, which is mainly used in nginx to intercept URLs containing /course/ and download files.
        ///course/ is also set in the second location of the above nginx configuration, the actual file download path does not include /course/
        //Of course, if you want to include it, you can change the above alias to 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.


    //If there is a Chinese file name or Chinese path, it needs to be encoded into iSO-8859-1
    //Otherwise, nginx will not be able to find the file and the pop-up file download box will also be garbled
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;
}
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326530264&siteId=291194637