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常用命令放入shell脚本详解
Mar 31 Servers
Nginx的rewrite模块详解
Mar 31 Servers
nginx实现发布静态资源的方法
Mar 31 Servers
Nginx 根据URL带的参数转发的实现
Apr 01 Servers
详解Apache SkyWalking 告警配置指南
Apr 22 Servers
教你利用Nginx 服务搭建子域环境提升二维地图加载性能的步骤
Sep 25 Servers
Nginx设置HTTPS的方法步骤 443证书配置方法
Mar 21 Servers
Windows Server 2016 配置 IIS 的详细步骤
Apr 28 Servers
搭建Yolov5服务器
Apr 30 Servers
Nginx 匹配方式
May 15 Servers
阿里云服务器部署RabbitMQ集群的详细教程
Jun 01 Servers
Docker部署Mysql8的实现步骤
Jul 07 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实现获取FLV文件的时间
2015/02/10 PHP
PHP使用内置函数file_put_contents写入文件及追加内容的方法
2015/12/07 PHP
PHP的Laravel框架中使用AdminLTE模板来编写网站后台界面
2016/03/21 PHP
PHP实践教程之过滤、验证、转义与密码详解
2017/07/24 PHP
IE与Firefox在JavaScript上的7个不同句法分享
2011/10/30 Javascript
javascript为下拉列表动态添加数据项
2014/05/23 Javascript
js实现的页面矩阵图形变换特效
2016/01/26 Javascript
js获取新浪天气接口的实现代码
2016/06/06 Javascript
bootstrap导航栏、下拉菜单、表单的简单应用实例解析
2017/01/06 Javascript
浅谈vue+webpack项目调试方法步骤
2017/09/11 Javascript
vue axios 表单提交上传图片的实例
2018/03/16 Javascript
深入浅出理解JavaScript闭包的功能与用法
2018/08/01 Javascript
利用原生的JavaScript实现简单拼图游戏
2018/11/18 Javascript
Bootstarp在pycharm中的安装及简单的使用方法
2019/04/19 Javascript
微信小程序动态设置图片大小的方法
2019/11/21 Javascript
javascript实现倒计时效果
2020/02/17 Javascript
Linux下将Python的Django项目部署到Apache服务器
2015/12/24 Python
详解Python爬虫的基本写法
2016/01/08 Python
详解Python下ftp上传文件linux服务器
2018/06/21 Python
Linux下python3.6.1环境配置教程
2018/09/26 Python
Python使用jpype模块调用jar包过程解析
2020/07/29 Python
CSS3的calc()做响应模式布局的实现方法
2017/09/06 HTML / CSS
详解前端HTML5几种存储方式的总结
2016/12/27 HTML / CSS
英国知名的护肤彩妆与时尚配饰大型综合零售电商:Unineed
2016/11/21 全球购物
Tomcat Mysql datasource数据源配置
2015/12/28 面试题
Solaris操作系统的线程机制
2015/07/28 面试题
入党自我鉴定范文
2013/10/04 职场文书
外贸业务员工作职责
2014/01/06 职场文书
高三体育教学反思
2014/01/29 职场文书
员工薪酬激励方案
2014/06/13 职场文书
师范类求职信
2014/06/21 职场文书
个人反四风对照检查材料思想汇报
2014/09/23 职场文书
党的群众路线教育实践活动自我剖析材料
2014/10/08 职场文书
2015年感恩母亲节的演讲稿
2015/03/18 职场文书
2016入党积极分子党校培训心得体会
2016/01/06 职场文书
创业计划书之校园超市
2019/09/12 职场文书