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
使用 Apache Superset 可视化 ClickHouse 数据的两种方法
Jul 07 Servers
nginx配置虚拟主机的详细步骤
Jul 21 Servers
详解使用内网穿透工具Ngrok代理本地服务
Mar 31 Servers
阿里云 Windows server 2019 配置FTP
Apr 28 Servers
Vscode中SSH插件如何远程连接Linux
May 02 Servers
项目中Nginx多级代理是如何获取客户端的真实IP地址
May 30 Servers
CentOS7安装MySQL8的超级详细教程(无坑!)
Jun 10 Servers
windows server 2012安装FTP并配置被动模式指定开放端口
Jun 10 Servers
win sever 2022如何占用操作主机角色
Jun 25 Servers
彻底卸载VMware虚拟机的超详细步骤记录
Jul 15 Servers
Centos7 Shell编程之正则表达式、文本处理工具详解
Aug 05 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
使用Apache的rewrite技术
2006/06/22 PHP
生成静态页面的PHP类
2006/07/15 PHP
一个简易需要注册的留言版程序
2006/10/09 PHP
PHP关于htmlspecialchars、strip_tags、addslashes的解释
2014/07/04 PHP
php 伪造ip以及url来路信息方法汇总
2014/11/25 PHP
php通过function_exists检测函数是否存在的方法
2015/03/18 PHP
非阻塞动态加载javascript广告实现代码
2010/11/17 Javascript
ExtJS[Desktop]实现图标换行示例代码
2013/11/17 Javascript
jquery live()重复绑定的解决方法介绍
2014/01/03 Javascript
js取模(求余数)隔行变色
2014/05/15 Javascript
JavaScript不刷新实现浏览器的前进后退功能
2014/11/05 Javascript
jQuery函数map()和each()介绍及异同点分析
2014/11/08 Javascript
原生JS实现仿淘宝网左侧商品分类菜单效果代码
2015/09/10 Javascript
jQuery拖动布局其结果保存到数据库
2015/10/09 Javascript
详谈javascript异步编程
2016/02/21 Javascript
js 实现数值的千分位及保存小数方法(推荐)
2016/08/01 Javascript
JavaScript DOM节点操作方法总结
2016/08/23 Javascript
如何实现json数据可视化详解
2016/11/24 Javascript
vue.js使用代理和使用Nginx来解决跨域的问题
2018/02/03 Javascript
vue-router3.0版本中 router.push 不能刷新页面的问题
2018/05/10 Javascript
详解redux异步操作实践
2018/08/15 Javascript
php结合js实现多条件组合查询
2019/05/28 Javascript
Javascript组合继承方法代码实例解析
2020/04/02 Javascript
javascript全局自定义鼠标右键菜单
2020/12/08 Javascript
django中ORM模型常用的字段的使用方法
2019/03/05 Python
Python实现的爬取百度贴吧图片功能完整示例
2019/05/10 Python
Pycharm无法打开双击没反应的问题及解决方案
2020/08/17 Python
用Python实现职工信息管理系统
2020/12/30 Python
Shopee马来西亚:随拍即卖,最佳行动电商拍卖平台
2017/06/05 全球购物
一组SQL面试题
2016/02/15 面试题
应届生财务管理求职信
2013/11/06 职场文书
区政府领导班子个人对照检查材料
2014/09/25 职场文书
旷课检讨书500字
2014/10/14 职场文书
居委会工作总结2015
2015/05/18 职场文书
离职证明格式样本
2015/06/12 职场文书
Python数据类型最全知识总结
2021/05/31 Python