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动态转换图片大小生成缩略图
Mar 31 Servers
nginx里的rewrite跳转的实现
Mar 31 Servers
Nginx配置https原理及实现过程详解
Mar 31 Servers
Nginx下配置Https证书详细过程
Apr 01 Servers
详解nginx进程锁的实现
Jun 14 Servers
图文详解Nginx版本平滑升级方案
Sep 15 Servers
Nginx+Windows搭建域名访问环境的操作方法
Mar 17 Servers
Windows Server 2012 R2 磁盘分区教程
Apr 29 Servers
IIS服务器中设置HTTP重定向访问HTTPS
Apr 29 Servers
Nginx HTTP跳转至HTTPS
May 15 Servers
利用Apache Common将java对象池化的问题
Jun 16 Servers
Linux中sftp常用命令整理
Jun 28 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处理SQL脚本文件导入到MySQL的代码实例
2014/03/17 PHP
php实现比较两个文件夹异同的方法
2015/06/18 PHP
PHP检测一个数组有没有定义的方法步骤
2019/07/20 PHP
Exjs 入门篇
2010/04/07 Javascript
javascript开发随笔二 动态加载js和文件
2011/11/25 Javascript
javascript级联下拉列表实例代码(自写)
2013/05/10 Javascript
JQuery中Ajax()的data参数类型实例分析
2015/12/15 Javascript
JQuery实现的按钮倒计时效果
2015/12/23 Javascript
原生JavaScript制作微博发布面板效果
2016/03/11 Javascript
JavaScript图像延迟加载库Echo.js
2016/04/05 Javascript
JS实现的适合做faq或menu滑动效果示例
2016/11/17 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
2017/03/30 jQuery
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
2017/06/26 jQuery
jQuery实现手机号正则验证输入及自动填充空格功能
2018/01/02 jQuery
详解webpack之scss和postcss-loader的配置
2018/01/09 Javascript
vue 对象添加或删除成员时无法实时更新的解决方法
2019/05/01 Javascript
vue2.0 实现富文本编辑器功能
2019/05/26 Javascript
基于jQuery实现挂号平台首页源码
2020/01/06 jQuery
[36:52]DOTA2真视界:基辅特锦赛总决赛
2017/05/21 DOTA
python 将字符串转换成字典dict
2013/03/24 Python
在树莓派2或树莓派B+上安装Python和OpenCV的教程
2015/03/30 Python
Python的装饰器模式与面向切面编程详解
2015/06/21 Python
实例介绍Python中整型
2019/02/11 Python
python利用Excel读取和存储测试数据完成接口自动化教程
2020/04/30 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
2020/06/18 Python
Python的scikit-image模块实例讲解
2020/12/30 Python
Expedia马来西亚旅游网站:廉价酒店,度假村和航班预订
2016/07/26 全球购物
健康监测猫砂:Pretty Litter
2017/05/25 全球购物
食品行业求职人的自我评价
2014/01/19 职场文书
企业员工培训感言
2014/02/26 职场文书
车间主任岗位职责
2014/03/16 职场文书
企业承诺书怎么写
2014/05/24 职场文书
2014个人反腐倡廉思想汇报
2014/09/15 职场文书
2016年优秀少先队辅导员事迹材料
2016/02/26 职场文书
windows11怎么查看自己安装的版本号? win11版本号的查看方法
2021/11/21 数码科技
Golang gRPC HTTP协议转换示例
2022/06/16 Golang