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配置Https安全认证的实现
May 26 Servers
Nginx反向代理学习实例教程
Oct 24 Servers
zabbix自定义监控nginx状态实现过程
Nov 01 Servers
Linux下使用C语言代码搭建一个简单的HTTP服务器
Apr 13 Servers
Window server 2012 R2 AD域的组策略相关设置
Apr 28 Servers
Win10 Anaconda安装python-pcl
Apr 29 Servers
Nginx静态压缩和代码压缩提高访问速度详解
May 30 Servers
nginx设置资源请求目录的方式详解
May 30 Servers
Nginx开源可视化配置工具NginxConfig使用教程
Jun 21 Servers
搭建zabbix监控以及邮件报警的超级详细教学
Jul 15 Servers
Nginx代理Redis哨兵主从配置的实现
Jul 15 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
url decode problem 解决方法
2011/12/26 PHP
mongo Table类文件 获取MongoCursor(游标)的实现方法分析
2013/07/01 PHP
phpExcel中文帮助手册之常用功能指南
2014/08/18 PHP
浅谈php命令行用法
2015/02/04 PHP
php实现删除空目录的方法
2015/03/16 PHP
php无限极分类实现方法分析
2019/07/04 PHP
PHP 裁剪图片
2021/03/09 PHP
用jQuery扩展自写的 UI导航
2010/01/13 Javascript
如何确保JavaScript的执行顺序 之实战篇
2011/03/03 Javascript
jquery实现的让超出显示范围外的导航自动固定屏幕最顶上
2011/09/22 Javascript
当jQuery1.7遇上focus方法的问题
2014/01/26 Javascript
javascript模块化简单解析
2016/04/07 Javascript
JavaScript原生节点操作小结
2017/01/17 Javascript
ES6中箭头函数的定义与调用方式详解
2017/06/02 Javascript
js异步编程小技巧详解
2017/08/14 Javascript
去掉vue 中的代码规范检测两种方法(Eslint验证)
2018/03/21 Javascript
原生javascript制作的拼图游戏实现方法详解
2020/02/23 Javascript
vue 解决setTimeOut和setInterval函数无效报错的问题
2020/07/30 Javascript
Python制作简易注册登录系统
2016/12/15 Python
Python并发编程协程(Coroutine)之Gevent详解
2017/12/27 Python
微信跳一跳自动运行python脚本
2018/01/08 Python
Python温度转换实例分析
2018/01/17 Python
Python实现爬虫抓取与读写、追加到excel文件操作示例
2018/06/27 Python
Python中应该使用%还是format来格式化字符串
2018/09/25 Python
Python中的引用知识点总结
2019/05/20 Python
Python中断多重循环的几种方式详解
2020/02/10 Python
python实现批处理文件
2020/07/28 Python
HTML5 canvas基本绘图之文字渲染
2016/06/27 HTML / CSS
化学教师教学反思
2014/01/17 职场文书
报纸媒体创意广告词
2014/03/17 职场文书
教师纪念9.18事件演讲稿范文
2014/09/14 职场文书
普通党员个人对照检查材料
2014/09/18 职场文书
安全先进个人材料
2014/12/29 职场文书
狼牙山五壮士观后感
2015/06/09 职场文书
python实现语音常用度量方法的代码详解
2021/05/25 Python
Vue 打包后相对路径的引用问题
2022/06/05 Vue.js