Nginx XSendfile + SpringMVC 기반 파일 다운로드

평소에 우리 가 파일 다운 로드 를 실현 하 는 것 은 보통 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 시 시스템 에서 두 번 의 메모리 복사 (총 네 번) 를 한다.링크 ux 에서 도입 한
sendfile 의 실제 상황 은 이 문 제 를 더욱 잘 해결 하기 위해 '제로 복사' 를 실현 하고 파일 다운로드 속 도 를 크게 향상 시킨다.
   
sendfile () 을 사용 하여 네트워크 파일 전송 성능 향상
   
RoR 사 이 트 는 lighttpd 의 X - sendfile 기능 을 어떻게 이용 하여 파일 다운로드 성능 을 향상 시 킵 니까?
  
    apache, nginx, lighttpd 등 웹 서버 에는 모두 sendfile feature 가 있 습 니 다.다음은 nginx 의 XSendfile 과 SpringMVC 파일 다운로드 및 접근 제어 에 대해 설명 합 니 다.우리 가 있 는 이곳 의 대체적인 절 차 는 다음 과 같다.
     1. 사용자 가 과제 다운로드 요청 을 시작 합 니 다.(http://dl.mydomain.com/download/courseware/1)      2. nginx 에서 이 (dl. my domain. com) 도 메 인 이름 의 요청 을 캡 처 합 니 다.     3. 프 록 시응용 서버 로 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;
	}
}

  
   
  

좋은 웹페이지 즐겨찾기