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的zabbix 5.0安装部署的方法步骤
Jul 16 Servers
教你利用Nginx 服务搭建子域环境提升二维地图加载性能的步骤
Sep 25 Servers
docker-compose部署Yapi的方法
Apr 08 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
如何Tomcat中使用ipv6地址
May 06 Servers
详解如何使用Nginx解决跨域问题
May 06 Servers
windows server 2016 域环境搭建的方法步骤(图文)
Jun 25 Servers
win sever 2022如何占用操作主机角色
Jun 25 Servers
Zabbix对Kafka topic积压数据监控的解决方案
Jul 07 Servers
zabbix 代理服务器的部署与 zabbix-snmp 监控问题
Jul 15 Servers
nginx配置指令之server_name的具体使用
Aug 14 Servers
zabbix如何添加监控主机和自定义监控项
Aug 14 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
PHP执行zip与rar解压缩方法实现代码
2010/12/05 PHP
基于PHP读取csv文件内容的详解
2013/06/18 PHP
提高PHP性能的编码技巧以及性能优化详细解析
2013/08/24 PHP
PHP树-不需要递归的实现方法
2016/06/21 PHP
php修改数组键名的方法示例
2017/04/15 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
详解PHP发送邮件知识点
2018/05/06 PHP
深入理解PHP+Mysql分布式事务与解决方案
2020/12/03 PHP
Jquery 表格合并的问题分享
2011/09/17 Javascript
jQuery设置与获取HTML,文本和值的简单实例
2014/02/26 Javascript
JS原型链怎么理解
2016/06/27 Javascript
AngularJS中比较两个数组是否相同
2016/08/24 Javascript
轻松掌握JavaScript代理模式
2016/08/26 Javascript
快速掌握jquery分页插件jqPaginator的使用方法
2017/08/09 jQuery
vue组件实现文字居中对齐的方法
2017/08/23 Javascript
分析JS单线程异步io回调的特性
2017/12/01 Javascript
layui-laydate时间日历控件使用方法详解
2018/11/15 Javascript
Vue中使用canvas方法总结
2019/02/12 Javascript
jQuery实现消息弹出框效果
2019/12/10 jQuery
在vue中实现清除echarts上次保留的数据(亲测有效)
2020/09/09 Javascript
vue-cli3项目配置eslint代码规范的完整步骤
2020/09/10 Javascript
[05:03]显微镜下的DOTA2第十期——Ti3豪之超神幽鬼
2014/06/23 DOTA
pyqt5 QlistView列表显示的实现示例
2020/03/24 Python
python删除某个目录文件夹的方法
2020/05/26 Python
css3学习之2D转换功能详解
2016/12/23 HTML / CSS
美国精品家居用品网站:US-Mattress
2016/08/24 全球购物
英国最大的高品质珠宝和手表专家:Goldsmiths
2017/03/11 全球购物
岗位廉洁从业承诺书
2014/03/28 职场文书
新法人代表任命书
2014/06/06 职场文书
乡镇党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
2015年度招聘工作总结
2015/05/28 职场文书
听证会主持词
2015/07/03 职场文书
2015年信息技术教研组工作总结
2015/07/22 职场文书
《打电话》教学反思
2016/02/22 职场文书
阿里云Nginx配置https实现域名访问项目(图文教程)
2021/03/31 Servers
HDFS免重启挂载新磁盘
2022/04/06 Servers