通过php的`header()`函数设置`content-disposition`为`attachment`并指定文件名,配合`readfile()`输出二进制流即可实现强制下载。为防止恶意ip高频请求导致服务器资源耗尽或带宽被刷爆,需要在脚本入口处引入基于ip地址的限流逻辑,利用redis等内存数据库记录访问频次,当请求超过阈值时直接终止脚本执行。

如何构建基础的强制下载接口
基础下载接口的核心在于正确设置HTTP响应头,告诉浏览器不要尝试解析文件内容,而是将其作为附件保存。需要设置`Content-Type`为`application/octet-stream`以屏蔽MIME类型猜测,设置`Content-Length`告知文件大小以便显示进度条,最后使用`readfile()`读取文件指针并输出到标准输出缓冲区。

\$filename = \"report.pdf\";\$filepath = \"/var/www/files/\" . \$filename;if (!file_exists(\$filepath)) { http_response_code(404); exit(\"File not found\");}header(\"Content-Description: File Transfer\");header(\"Content-Type: application/octet-stream\");header(\"Content-Disposition: attachment; filename=\".basename(\$filename));header(\"Expires: 0\");header(\"Cache-Control: must-revalidate\");header(\"Pragma: public\");header(\"Content-Length: \" . filesize(\$filepath));readfile(\$filepath);如何实现基于IP的防刷限流机制
在文件输出之前,必须拦截异常流量。通常的做法是获取客户端真实IP(考虑代理情况),然后查询Redis中该IP对应的计数器。如果计数器值大于设定的阈值(例如每秒5次),则立即返回错误信息并退出。每次成功通过检查的请求,都需要将计数器加1并设置一个短暂的过期时间(如1秒),从而实现滑动窗口或固定窗口的限流效果。
立即学习“PHP免费学习笔记(深入)”;

\$redis = new Redis();\$redis->connect('127.0.0.1', 6379);\$clientIp = $_SERVER['REMOTE_ADDR'];\$rateLimitKey = \"rate_limit:\" . \$clientIp;\$currentRequests = $redis->get($rateLimitKey);if ($currentRequests && $currentRequests > 5) { http_response_code(429); exit(\"Too many requests\");}$redis->incr($rateLimitKey);$redis->expire($rateLimitKey, 1); // Reset after 1 second限流失败时程序的具体行为是什么
当请求触发限流条件时,程序会调用`http_response_code(429)`设置状态码为“Too Many Requests”,随后执行`exit()`终止后续的文件读取和输出操作。此时浏览器端不会收到任何文件数据,而是接收到一个空的HTTP响应体,并伴随429状态码。开发者可以通过监听这个状态码在前端提示用户稍后重试,从而有效防止带宽被恶意耗尽。



















