Nginx使用X-Accel-Redirect实现静态文件下载的统计、鉴权、防盗链、限速等


Posted in Servers onApril 04, 2021

需求

  • 统计静态文件的下载次数;
  • 判断用户是否有下载权限;
  • 根据用户指定下载速度;
  • 根据Referer判断是否需要防盗链;
  • 根据用户属性限制下载速度;

X-Accel-Redirect

This allows you to handle authentication, logging or whatever else you please in your backend and then have NGINX handle serving the contents from redirected location to the end user, thus freeing up the backend to handle other requests. This feature is commonly known as X-Sendfile.
这个功能允许你在后端处理权限,日志或任何你想干的,Nginx提供内容服务给终端用户从重定向后的路径,因此可以释放后端去处理其他请求(直接由Nginx提供IO,而不是后端服务)。这个功能类似 X-Sendfile 。

不同 Web 服务器,相同功能,不同的标识:

nginx: X-Accel-Redirect 
squid: X-Accelerator-Vary 
apache: X-Sendfile 
lighttpd: X-Sendfile/X-LIGHTTPD-send-file 

X-Accel-Limit-Rate

限制下载速度,单位字节。默认不限速度。

X-Accel-Buffering

设置此连接的代理缓存,将此设置为no将允许适用于Comet和HTTP流式应用程序的无缓冲响应。将此设置为yes将允许响应被缓存。默认yes。

X-Accel-Expires

如果已传输过的文件被缓存下载,设置Nginx文件缓存过期时间,单位秒。默认不过期。

X-Accel-Charset

设置文件字符集,默认utf-8。

使用条件

  • 必须有Nginx作为后端服务的代理;
  • 必须访问Nginx的代理地址,直接访问后端服务Nginx会报404;
  • 可自行配置Content-Type来控制是下载(application/octet-stream)还是展示(image/jpeg等);

代码实现

  1. Nginx监听15555端口。
  2. Nginx代理后端服务的18000端口。
  3. 设置/file路径为internal,指定具体文件存储的磁盘位置。
  4. 后端服务接收到文件下载请求,处理业务逻辑后X-Accel-Redirect/file路径。
  5. Nginx收到后端返回信息中的X-Accel-Redirect请求头,接管文件下载任务。
  6. 请求路径:http://localhost:15555/f/1.jpg

Java-SpringMVC版本

Nginx配置

server {
    listen 15555;

    location / {
        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;
        proxy_pass http://127.0.0.1:18000/;            
    }

    location /file {
        internal;
        alias /data/file;
    }
}

Java代码

注意fileName添加:.+,或者获取不到文件后缀名。

@GetMapping(value = "/f/{fileName:.+}")
public void file(@PathVariable String fileName, HttpServletResponse response, HttpServletRequest request) throws IOException {
    //统计
    //鉴权
    //判断Referer
    String referer = request.getHeader("Referer");
    if (referer == null || !referer.startsWith("https://www.zhangbj.com")) {
        response.sendError(403, "Forbidden");
        return;
    }
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    response.setHeader("Content-Type", "application/octet-stream");
    response.setHeader("X-Accel-Redirect","/file/" + fileName);
    response.setHeader("X-Accel-Limit-Rate","1024");//限速,单位字节,默认不限
    response.setHeader("X-Accel-Buffering","yes");//是否使用Nginx缓存,默认yes
}

PHP-ThinkPHP版本

Nginx配置

server {
    listen  80;
    server_name  localhost;
    root   D:/z-blog/public;
    location / {
        index  index.html index.htm index.php;
        if (!-e $request_filename) {
            rewrite  ^(.*)$  /index.php?s=/$1  last;
            break;
        }
    }

    location ~ \.php(.*)$ {
        fastcgi_pass   127.0.0.1:9500;
        fastcgi_index  index.php;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO  $fastcgi_path_info;
        fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
        include        fastcgi_params;
    }

    location /file {
        internal;
        alias D:/file;
    }
}

ThinkPHP代码

Router:

Route::get('/f/:fileName', 'index/File/file');

Controller:

<?php

namespace app\index\controller;

use think\Request;

class File {
    public function file($fileName) {
        $request = Request::instance();
        $referer = $request->header('referer');
        if (!$referer || strpos($referer, 'https://www.zhangbj.com') !== 0) {
            header("Status:403 Forbidden");
            return;
        }
        header('Content-type: application/octet-stream');
        header("Content-Disposition: attachment; filename=$fileName");
        header("X-Accel-Redirect:  /file/$fileName");
    }
}

参考

Nginx: X-Accel-Redirect

Nginx: XSendfile

Servers 相关文章推荐
Nginx的rewrite模块详解
Mar 31 Servers
查看nginx配置文件路径和资源文件路径的方法
Mar 31 Servers
Nginx已编译的nginx-添加新模块
Apr 01 Servers
Nginx配置Https安全认证的实现
May 26 Servers
nginx内存池源码解析
Nov 20 Servers
图文详解nginx日志切割的实现
Jan 18 Servers
Nginx图片服务器配置之后图片访问404的问题解决
Mar 21 Servers
Apache Hudi集成Spark SQL操作hide表
Mar 31 Servers
Docker 镜像介绍以及commit相关操作
Apr 13 Servers
WinServer2012搭建DNS服务器的方法步骤
Jun 10 Servers
win7配置本地ftp服务器的图文教程
Aug 05 Servers
Nginx工作原理和优化总结。
利用Nginx代理如何解决前端跨域问题详析
Apr 02 #Servers
Nginx URL重写rewrite机制原理及使用实例
Apr 01 #Servers
nginx限制并发连接请求数的方法
Apr 01 #Servers
Nginx已编译的nginx-添加新模块
Nginx下配置Https证书详细过程
详解Nginx启动失败的几种错误处理
Apr 01 #Servers
You might like
Admin generator, filters and I18n
2011/10/06 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
2012/06/17 PHP
Zend Framework数据库操作技巧总结
2017/02/18 PHP
关于IFRAME 自适应高度的研究
2006/07/20 Javascript
用JavaScript显示随机图像或引用
2009/04/21 Javascript
Javascript的并行运算实现代码
2010/11/19 Javascript
使用jQuery判断IE浏览器版本的代码
2014/06/14 Javascript
用js编写的简单的计算器代码程序
2015/08/04 Javascript
JavaScript 冒泡排序和选择排序的实现代码
2016/09/03 Javascript
angularjs $http实现form表单提交示例
2017/06/09 Javascript
深究AngularJS中ng-drag、ng-drop的用法
2017/06/12 Javascript
Angular.js中$resource高大上的数据交互详解
2017/07/30 Javascript
js HTML5 canvas绘制图片的方法
2017/09/08 Javascript
详解JS模块导入导出
2017/12/20 Javascript
在vue中使用setInterval的方法示例
2019/04/16 Javascript
详解Vue调用手机相机和相册以及上传
2019/05/05 Javascript
记录vue项目中遇到的一点小问题
2019/05/14 Javascript
微信小程序判断页面是否从其他页面返回的实例代码
2019/07/03 Javascript
微信小程序实现导航栏和内容上下联动功能代码
2020/06/29 Javascript
python发送邮件的实例代码(支持html、图片、附件)
2013/03/04 Python
Python中的集合类型知识讲解
2015/08/19 Python
Python实现简单登录验证
2016/04/13 Python
Python读取MRI并显示为灰度图像实例代码
2018/01/03 Python
python正则实现提取电话功能
2018/02/24 Python
基于Pandas读取csv文件Error的总结
2018/06/15 Python
解决pyinstaller打包exe文件出现命令窗口一闪而过的问题
2018/10/31 Python
解决Pytorch 训练与测试时爆显存(out of memory)的问题
2019/08/20 Python
美体小铺瑞典官方网站:The Body Shop瑞典
2018/01/27 全球购物
培训主管的岗位职责
2013/11/23 职场文书
纪念九一八爱国演讲稿600字
2014/09/14 职场文书
领导干部贪图享乐整改措施
2014/09/21 职场文书
县政府班子个人对照检查材料
2014/10/05 职场文书
教师工作总结范文2014
2014/11/10 职场文书
教师继续教育反思周记
2015/06/25 职场文书
2019感恩宣传标语!
2019/07/05 职场文书
Shell脚本一键安装Nginx服务自定义Nginx版本
2022/03/20 Servers