expires指令不能直接写在http块顶层,因它属输出过滤类指令,需请求处理上下文;正确做法是用map预定义缓存变量再于location中引用,或通过include复用配置。

在Nginx中,expires指令本身**不能直接写在http块顶层作为全局默认配置**来自动作用于所有server块——它必须出现在server、location或if上下文中。但通过合理结构设计,可以实现“类全局”的统一缓存控制效果,避免重复配置。
为什么不能直接在http块里用expires
Nginx的配置解析机制决定了expires属于“输出过滤类”指令,依赖于具体的请求处理上下文(如响应头生成、MIME类型判断、是否启用gzip等),而http块层级尚未进入具体请求匹配阶段。若强行写入,Nginx会报错:“expires directive is not allowed here”。
推荐的多Server统一缓存方案
以下方式兼顾可维护性、灵活性与安全性:
-
使用include + 公共location配置文件:将常用静态资源缓存规则抽离为独立文件(如
/etc/nginx/conf.d/expiry.conf),在每个server块内用include引入 -
按MIME类型集中设置(推荐):在
http块中使用map指令预定义缓存时间变量,再在各location中引用,实现逻辑统一 -
利用default_server的兜底location:对未显式配置缓存的
server,可通过location匹配通用后缀(如.js、.css)并设默认expires
实用示例:基于map的统一缓存控制
在http块中添加:
map $sent_http_content_type $expires_time {
default off;
~*^text/ 1h;
~*application/javascript 1h;
~*application/css 1h;
~*image/ 1w;
~*font/ 1y;
}然后在任意server或location中写入:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot)$ {
expires $expires_time;
}这样既避免重复定义时间值,又保留各server的定制自由度(比如某个站点图片需缓存更久,可单独覆盖$expires_time变量)。
注意事项与避坑点
实际部署中需留意:
-
expires仅对状态码为200、201、204、206、301、302、303、304、307的响应生效;对5xx或4xx错误页无效 - 若同时启用
gzip,确保expires在gzip之后生效(Nginx内部顺序已保证,无需调整) - 动态内容(如PHP、proxy_pass)不建议盲目加
expires,除非确认响应确实可缓存且有明确过期策略 - 使用
add_header Cache-Control时注意与expires协同:后者会自动设置Cache-Control: max-age=和Expires头,前者若冲突可能被覆盖

















