在Nginx中使用X-Sendfile头提升PHP文件下载的性能(针对大文件下载)

 更新时间:2014年07月04日 12:06:56   投稿:junjie  
这篇文章主要介绍了在Nginx中使用X-Sendfile头提升PHP文件下载的性能,可以用在针对大文件下载的情况,下载非网站Web目录文件的需求,提供下载权限控制的场景,需要的朋友可以参考下

很多时候用户需要从网站下载文件,如果文件是可以通过一个固定链接公开获取的,那么我们只需将文件存放到 webroot下的目录里就好。但大多数情况下,我们需要做权限控制,例如下载 PDF 账单,又例如下载网盘里的档案。这时,我们通常借助于脚本代码来实现,而这无疑会增加服务器的负担。

例如下面的代码:

<?php
  // 用户身份认证,若验证失败跳转
  authenticate();
  // 获取需要下载的文件,若文件不存在跳转
  $file = determine_file();
  // 读取文件内容
  $content=file_get_contents($file);
  // 发送合适的 HTTP 头
  header("Content-type: application/octet-stream");
  header('Content-Disposition: attachment; filename="' . basename($file) . '"');
  header("Content-Length: ". filesize($file));
  echo $content; // 或者 readfile($file);
?>

一、这样做有什么问题?

这样做意味着我们的程序需要将文件内容从磁盘经过一个固定的 buffer 去循环读取到内存,再发送给前端 web 服务器,最后才到达用户。当需要下载的文件很大的时候,这种方式将消耗大量内存,甚至引发 php 进程超时或崩溃。Cache 也很头疼,更不用说中断重连的情况了。
一个理想的解决方式应该是,由 php 程序进行权限检查等逻辑判断,一切通过后,让前台的 web 服务器直接将文件发送给用户——像 Nginx 这样的前台更善于处理静态文件。这样一来 php 脚本就不会被 I/O 阻塞了。

二、什么是 X-Sendfile?

X-Sendfile 是一种将文件下载请求由后端应用转交给前端 web 服务器处理的机制,它可以消除后端程序既要读文件又要处理发送的压力,从而显著提高服务器效率,特别是处理大文件下载的情形下。

X-Sendfile 通过一个特定的 HTTP header 来实现:在 X-Sendfile 头中指定一个文件的地址来通告前端 web 服务器。当 web 服务器检测到后端发送的这个 header 后,它将忽略后端的其他输出,而使用自身的组件(包括 缓存头 和 断点重连 等优化)机制将文件发送给用户。

不过,在使用 X-Sendfile 之前,我们必须明白这并不是一个标准特性,在默认情况下它是被大多数 web 服务器禁用的。而不同的 web 服务器的实现也不一样,包括规定了不同的 X-Sendfile 头格式。如果配置失当,用户可能下载到 0 字节的文件。

使用 X-Sendfile 将允许下载非 web 目录中的文件(例如/root/),即使文件在 .htaccess 保护下禁止访问,也会被下载。

不同的 web 服务器实现了不同的 HTTP 头

SENDFILE 头 使用的 WEB 器
X-Sendfile Apache, Lighttpd v1.5, Cherokee
X-LIGHTTPD-send-file Lighttpd v1.4
X-Accel-Redirect Nginx, Cherokee

使用 X-SendFile 的缺点是你失去了对文件传输机制的控制。例如如果你希望在完成文件下载后执行某些操作,比如只允许用户下载文件一次,这个 X-Sendfile 是没法做到的,因为后台的 php 脚本并不知道下载是否成功。

三、怎样使用?

Apache 请参考mod_xsendfile模块。下面我介绍 Nginx 的用法。

Nginx 默认支持该特性,不需要加载额外的模块。只是实现有些不同,需要发送的 HTTP 头为 X-Accel-Redirect。另外,需要在配置文件中做以下设定

location /protected/ {
 internal;
 root  /some/path;
}

表示这个路径只能在 Nginx 内部访问,不能用浏览器直接访问防止未授权的下载。


于是 PHP 发送 X-Accel-Redirect 给 Nginx:

]<?php
  $filePath = '/protected/iso.img';
  header('Content-type: application/octet-stream');
  header('Content-Disposition: attachment; filename="' . basename($file) . '"');
  //让Xsendfile发送文件
  header('X-Accel-Redirect: '.$filePath);
?>

这样用户就会下载到 /some/path/protected/iso.img 这个路径下的文件。
如果你想发送的是 /some/path/iso.img 文件,那么 Nginx 配置应该是

location /protected/ {
 internal;
 alias  /some/path/; # 注意最後的斜杠
}

相关文章

  • Nginx常用配置以及代理转发操作详解

    Nginx常用配置以及代理转发操作详解

    这篇文章主要给大家介绍了关于Nginx常用配置以及代理转发的相关资料,nginx一般被用来做反向代理,将请求转发到应用服务器上,比如tomcat的应用,需要的朋友可以参考下
    2023-09-09
  • Nginx利用Logrotate实现日志分割的详细过程

    Nginx利用Logrotate实现日志分割的详细过程

    nginx日志分割是很常见的运维工作,下面这篇文章主要给大家介绍了关于Nginx利用Logrotate日志分割的详细过程,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • 为Nginx服务器配置黑名单或白名单功能的防火墙

    为Nginx服务器配置黑名单或白名单功能的防火墙

    这篇文章主要介绍了为Nginx服务器配置黑名单或白名单功能的防火墙的方法,文中还附带介绍了一个基于lua的第三方防火墙模块,需要的朋友可以参考下
    2016-01-01
  • nginx上部署react项目的实例方法

    nginx上部署react项目的实例方法

    今天小编就为大家分享一篇关于nginx上部署react项目的实例方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-02-02
  • 添加Nginx代理配置只允许内部IP访问的实现方法

    添加Nginx代理配置只允许内部IP访问的实现方法

    在本篇文章里小编给大家整理的是一篇关于添加Nginx代理配置只允许内部IP访问的实现方法的文章,有需要的朋友们可以学习下。
    2019-10-10
  • Nginx服务500:Internal Server Error原因之一

    Nginx服务500:Internal Server Error原因之一

    这篇文章主要介绍了Nginx服务500:Internal Server Error原因之一,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • 配置Nginx实现访问本地静态资源的完整指南

    配置Nginx实现访问本地静态资源的完整指南

    Nginx 是一个高性能的 HTTP 服务器和反向代理服务器,广泛用于静态资源的托管和负载均衡,在开发和生产环境中,我们常常需要使用 Nginx 来提供本地静态资源的访问,本文将详细介绍如何配置 Nginx 以便访问本地静态资源,需要的朋友可以参考下
    2024-08-08
  • nginx重写和重定向关系与配置方式

    nginx重写和重定向关系与配置方式

    这篇文章主要介绍了nginx重写和重定向关系与配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 使用Nginx搭载rtmp直播服务器的方法

    使用Nginx搭载rtmp直播服务器的方法

    这次我们搭建一个rtmp直播服务器,用于电脑或手机直播推流到服务器,然后其他终端如电脑或手机可以观看直播的视频画面。接下来通过本文给大家分享使用Nginx搭载rtmp直播服务器的问题,感兴趣的朋友一起看看吧
    2021-10-10
  • CentOS 中Nginx的安装方法

    CentOS 中Nginx的安装方法

    最近研究LNMP,首先要在linux下配置nginx服务器,废话少说,下面给大家分享下在CentOS 中Nginx的安装方法
    2017-08-08

最新评论