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配置虚拟主机的详细步骤
Jul 21 Servers
Nginx+Windows搭建域名访问环境的操作方法
Mar 17 Servers
Consul在linux环境的集群部署
Apr 08 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
Mac电脑OS系统下安装Nginx的详细教程
Apr 14 Servers
nginx配置之并发频次限制
Apr 18 Servers
微信告警的zabbix监控系统 监控整个NGINX集群
Apr 18 Servers
Vscode中SSH插件如何远程连接Linux
May 02 Servers
详解apache编译安装httpd-2.4.54及三种风格的init程序特点和区别
Jul 15 Servers
Windows7下FTP搭建图文教程
Aug 05 Servers
Shell中的单中括号和双中括号的用法详解
Dec 24 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进行批量任务处理不超时的解决方法
2016/07/11 PHP
Zend Framework处理Json数据方法详解
2016/12/09 PHP
Laravel实现定时任务的示例代码
2017/08/10 PHP
Swoole4.4协程抢占式调度器详解
2019/05/23 PHP
用js得到网页中所有的div的id
2020/10/19 Javascript
jquery插件之easing使用
2010/08/19 Javascript
jquery实现输入框动态增减的实例代码
2013/07/14 Javascript
JS读取XML文件示例代码
2013/11/15 Javascript
js的hasownproperty使用示例
2014/03/02 Javascript
百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换
2016/02/19 Javascript
Bootstrap媒体对象的实现
2016/05/01 Javascript
js获取html的span标签的值方法(超简单)
2016/07/26 Javascript
详解堆的javascript实现方法
2016/11/29 Javascript
bootstrap fileinput组件整合Springmvc上传图片到本地磁盘
2017/05/11 Javascript
jQuery返回定位插件详解
2017/05/15 jQuery
JS 学习总结之正则表达式的懒惰性和贪婪性
2017/07/03 Javascript
提高Node.js性能的应用技巧分享
2017/08/10 Javascript
jQuery取得元素标签名称小结(附代码)
2017/08/16 jQuery
js使用highlight.js高亮你的代码
2017/08/18 Javascript
js传递数组参数到后台controller的方法
2018/03/29 Javascript
js中getter和setter用法实例分析
2018/08/14 Javascript
Python中subprocess的简单使用示例
2015/07/28 Python
Python字典数据对象拆分的简单实现方法
2017/12/05 Python
Python3内置模块之base64编解码方法详解
2019/07/13 Python
使用Python实现文字转语音并生成wav文件的例子
2019/08/08 Python
python 实现图像快速替换某种颜色
2020/06/04 Python
Java和Javasciprt的区别
2012/09/02 面试题
促销活动方案模板
2014/02/24 职场文书
竞选班干部的演讲稿
2014/04/24 职场文书
企业职业病防治方案
2014/05/29 职场文书
交通事故和解协议书
2015/01/27 职场文书
仓库保管员岗位职责
2015/02/09 职场文书
学生会2016感恩节活动小结
2016/04/01 职场文书
python实现Thrift服务端的方法
2021/04/20 Python
Python制作春联的示例代码
2022/01/22 Python
Pandas实现批量拆分与合并Excel的示例代码
2022/05/30 Python