基于 Nginx XSendfile SpringMVC 验证登陆后文件下载

Colin 1年前 ⋅ 202 阅读

技术博客需要为注册用户提供示例代码附件的下载功能,同时又需要限制非登陆用户下载。而使用java文件流方式读取服务器文件又会消耗大量服务器内存资源,但是判断用户是否登陆的逻辑又需要编写java代码,所以使用Nginx和Java代码结合的方式来解决这个问题是一个比较不错的方案。

下段代码主要作用是springMVC Controller层判断和校验用户是否登陆,未登陆跳转到登陆页面/login;否则,将文件名以及相对路径写入响应头,交由Nginx转发。

...
@Controller
public class DownloadsController extends BaseController {
 
	/**
	 * 
	 * @param filename 文件名称
	 * @throws IOException
	 */
	@RequestMapping("/download/{filename}")
	public void download(@PathVariable("filename") String filename, HttpServletResponse response) throws IOException {
		System.out.println("filename::::" + filename);
		System.out.println((!isAuthenticated()));
		if (!isAuthenticated()) {
			// 未登录跳转至登陆页面;
			response.sendRedirect("/login");
		} else { 
			// 假如用户已经登录,将文件路径信息写入响应头;
			String encoding = response.getCharacterEncoding();
			response.setHeader("X-Accel-Charset", "utf-8");
			response.setHeader("Content-Type", "application/octet-stream");
			response.setHeader("X-Accel-Redirect", "/downloads/" + toPathEncoding(encoding, filename));
			response.setHeader("Content-Disposition", "attachment; filename=" + toPathEncoding(encoding, filename));
		}
	}

	// 如果存在中文文件名或中文路径需要对其进行编码成 iSO-8859-1
	// 否则会导致 nginx无法找到文件及弹出的文件下载框也会乱码
	private String toPathEncoding(String origEncoding, String fileName) throws UnsupportedEncodingException {
		return new String(fileName.getBytes(origEncoding), DEFAULT_FILE_ENCODING);
	}

}

Controller层主要提供了/download/文件名,这样一个请求接口,接受一个文件名,然后将X-Accel-Redirect传入响应头,Nginx在拦截到包含X-Accel-Redirect的响应后会访问X-Accel-Redirect所指向的路径/downloads/文件名称,注意:这里是downloads,Nginx配置文件中也需要配置一个downloads的路径,将downloads/请求设定为internal(内部请求,浏览器无法直接访问),并且转发到服务器指定目录(/data/downloads)。

执行vi /etc/nginx/nginx.cfg,在server配置块中添加如下配置:

location /downloads/ 
{
       charset utf-8;
       alias   /data/downloads/;
       internal;
       access_log /home/log/nginx/download.log;

}

 

做好这一切之后,我们只需要将需要公开的附件上传到服务器的/data/downloads/目录下即可。而下载的链接则是/download/具体文件名称.后缀,请求该资源后,若未登录则提示登陆,已经登陆则直接可以请求到文件资源。并且文件的下载是以静态资源的方式,走的Nginx。

 

全部评论: 0

    我有话说: