Appearance
NGINX 伪静态与路径重写指南
NGINX 的伪静态和路径重写功能是 Web 服务器配置中的重要组成部分,它能够美化 URL、隐藏真实文件路径、实现 SEO 友好的链接结构,以及处理各种重定向需求。
目录
什么是伪静态和路径重写
伪静态概念
伪静态是指将动态 URL 转换为静态 URL 的形式,但实际上仍然由动态程序处理。例如:
- 动态 URL:
/article.php?id=123 - 伪静态 URL:
/article/123.html
路径重写概念
路径重写是指将一个 URL 请求重写为另一个 URL,可以是内部重写(不改变浏览器地址栏)或外部重定向(改变浏览器地址栏)。
rewrite 指令详解
基本语法
nginx
rewrite regex replacement [flag];参数说明
- regex: 正则表达式,用于匹配请求的 URI
- replacement: 重写后的 URI
- flag: 可选标志,控制重写行为
常用标志
nginx
# last - 停止处理当前请求,重新开始匹配 location
rewrite ^/old/(.*)$ /new/$1 last;
# break - 停止处理当前请求,继续处理
rewrite ^/old/(.*)$ /new/$1 break;
# redirect - 返回 302 临时重定向
rewrite ^/old/(.*)$ /new/$1 redirect;
# permanent - 返回 301 永久重定向
rewrite ^/old/(.*)$ /new/$1 permanent;正则表达式基础
nginx
# 常用正则表达式符号
^ # 字符串开始
$ # 字符串结束
. # 任意字符
* # 零次或多次
+ # 一次或多次
? # 零次或一次
\d # 数字
\w # 字母、数字、下划线
() # 分组捕获
[] # 字符集
| # 或location 指令与重写
location 匹配规则
nginx
# 精确匹配
location = /exact {
# 只匹配 /exact
}
# 前缀匹配(优先)
location ^~ /prefix {
# 匹配以 /prefix 开头的 URL
}
# 正则匹配
location ~ \.php$ {
# 匹配以 .php 结尾的 URL
}
# 正则匹配(不区分大小写)
location ~* \.(jpg|jpeg|png|gif)$ {
# 匹配图片文件
}
# 普通前缀匹配
location /normal {
# 匹配以 /normal 开头的 URL
}location 优先级
=精确匹配^~前缀匹配~和~*正则匹配(按配置顺序)- 普通前缀匹配
常见重写场景
1. 去除文件扩展名
nginx
# 去除 .html 扩展名
location / {
rewrite ^/(.*)\.html$ /$1 last;
try_files $uri $uri.html $uri/ =404;
}
# 去除 .php 扩展名
location / {
rewrite ^/(.*)\.php$ /$1 last;
try_files $uri $uri.php $uri/ =404;
}2. 添加文件扩展名
nginx
# 自动添加 .html 扩展名
location / {
try_files $uri $uri.html $uri/ =404;
}
# 自动添加 .php 扩展名
location / {
try_files $uri $uri.php $uri/ =404;
}3. 文章详情页重写
nginx
# WordPress 风格的文章 URL
location / {
rewrite ^/article/(\d+)$ /article.php?id=$1 last;
rewrite ^/article/(\d+)/(.*)$ /article.php?id=$1&slug=$2 last;
}
# 自定义文章 URL
location / {
rewrite ^/post/([a-zA-Z0-9-]+)$ /post.php?slug=$1 last;
rewrite ^/post/(\d{4})/(\d{2})/([a-zA-Z0-9-]+)$ /post.php?year=$1&month=$2&slug=$3 last;
}4. 分类页面重写
nginx
# 分类页面
location / {
rewrite ^/category/([a-zA-Z0-9-]+)$ /category.php?name=$1 last;
rewrite ^/category/([a-zA-Z0-9-]+)/page/(\d+)$ /category.php?name=$1&page=$2 last;
}
# 标签页面
location / {
rewrite ^/tag/([a-zA-Z0-9-]+)$ /tag.php?name=$1 last;
rewrite ^/tag/([a-zA-Z0-9-]+)/page/(\d+)$ /tag.php?name=$1&page=$2 last;
}5. 用户页面重写
nginx
# 用户个人页面
location / {
rewrite ^/user/([a-zA-Z0-9_-]+)$ /user.php?username=$1 last;
rewrite ^/user/([a-zA-Z0-9_-]+)/profile$ /user.php?username=$1&page=profile last;
rewrite ^/user/([a-zA-Z0-9_-]+)/posts$ /user.php?username=$1&page=posts last;
}6. 搜索页面重写
nginx
# 搜索页面
location / {
rewrite ^/search/(.*)$ /search.php?q=$1 last;
rewrite ^/search/(.*)/page/(\d+)$ /search.php?q=$1&page=$2 last;
}7. 多语言支持
nginx
# 语言前缀重写
location / {
rewrite ^/(en|zh|ja)/(.*)$ /$2?lang=$1 last;
rewrite ^/(en|zh|ja)$ /?lang=$1 last;
}
# 语言子目录重写
location / {
rewrite ^/en/(.*)$ /$1?lang=en last;
rewrite ^/zh/(.*)$ /$1?lang=zh last;
rewrite ^/ja/(.*)$ /$1?lang=ja last;
}8. API 重写
nginx
# RESTful API 重写
location /api/ {
rewrite ^/api/users/(\d+)$ /api/user.php?id=$1 last;
rewrite ^/api/users/(\d+)/posts$ /api/user_posts.php?user_id=$1 last;
rewrite ^/api/posts/(\d+)$ /api/post.php?id=$1 last;
rewrite ^/api/posts/(\d+)/comments$ /api/post_comments.php?post_id=$1 last;
}
# 版本化 API
location /api/ {
rewrite ^/api/v1/(.*)$ /api/v1/$1 last;
rewrite ^/api/v2/(.*)$ /api/v2/$1 last;
}9. 静态资源重写
nginx
# 版本化静态资源
location /static/ {
rewrite ^/static/(\d+\.\d+\.\d+)/(.*)$ /static/$2 last;
}
# CDN 回源重写
location /cdn/ {
rewrite ^/cdn/(.*)$ /static/$1 last;
}10. 旧链接重定向
nginx
# 301 永久重定向
location / {
rewrite ^/old-page$ /new-page permanent;
rewrite ^/old-category/(.*)$ /new-category/$1 permanent;
}
# 302 临时重定向
location / {
rewrite ^/temp-page$ /new-page redirect;
}高级重写技巧
1. 条件重写
nginx
# 基于请求方法的重写
location / {
if ($request_method = POST) {
rewrite ^/api/(.*)$ /api/post/$1 last;
}
if ($request_method = GET) {
rewrite ^/api/(.*)$ /api/get/$1 last;
}
}
# 基于 User-Agent 的重写
location / {
if ($http_user_agent ~* "Mobile|Android|iPhone") {
rewrite ^/(.*)$ /mobile/$1 last;
}
}2. 参数处理
nginx
# 保留查询参数
location / {
rewrite ^/article/(\d+)$ /article.php?id=$1&$args last;
}
# 添加默认参数
location / {
rewrite ^/search$ /search.php?q=&page=1 last;
rewrite ^/search/(.*)$ /search.php?q=$1&page=1 last;
}3. 复杂正则表达式
nginx
# 多级目录重写
location / {
rewrite ^/([a-z]{2})/([a-z]+)/(\d{4})/(\d{2})/([a-zA-Z0-9-]+)$ /article.php?lang=$1&category=$2&year=$3&month=$4&slug=$5 last;
}
# 可选参数重写
location / {
rewrite ^/product/([a-zA-Z0-9-]+)(?:/(\d+))?$ /product.php?slug=$1&page=$2 last;
}4. 内部重写与外部重定向
nginx
# 内部重写(不改变浏览器地址)
location / {
rewrite ^/internal/(.*)$ /app/$1 last;
}
# 外部重定向(改变浏览器地址)
location / {
rewrite ^/external/(.*)$ /new/$1 permanent;
}5. 错误页面重写
nginx
# 自定义错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
internal;
rewrite ^/404.html$ /error/404.php last;
}
location = /50x.html {
internal;
rewrite ^/50x.html$ /error/50x.php last;
}性能优化
1. 重写规则优化
nginx
# 避免过多的重写规则
location / {
# 使用 try_files 替代部分重写
try_files $uri $uri.html $uri.php $uri/ =404;
}
# 使用 map 指令优化
map $uri $rewrite_uri {
default "";
~^/article/(\d+)$ /article.php?id=$1;
~^/category/([a-zA-Z0-9-]+)$ /category.php?name=$1;
}
location / {
if ($rewrite_uri != "") {
rewrite ^ $rewrite_uri last;
}
}2. 缓存优化
nginx
# 静态资源缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 重写后的页面缓存
location ~ \.php$ {
fastcgi_cache my_cache;
fastcgi_cache_valid 200 1h;
fastcgi_cache_key "$request_method$request_uri";
}3. 日志优化
nginx
# 自定义日志格式
log_format rewrite_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rewrite: "$uri" -> "$request_uri"';
# 重写规则日志
location / {
rewrite ^/article/(\d+)$ /article.php?id=$1 last;
access_log /var/log/nginx/rewrite.log rewrite_log;
}故障排除
1. 常见错误
nginx
# 重写循环
location / {
# 错误:可能导致循环
rewrite ^/(.*)$ /$1 last;
# 正确:添加条件避免循环
rewrite ^/(.*)$ /$1 last;
if ($uri != $request_uri) {
return 500;
}
}2. 调试技巧
nginx
# 启用重写日志
rewrite_log on;
error_log /var/log/nginx/rewrite.log notice;
# 测试重写规则
location /test/ {
rewrite ^/test/(.*)$ /debug.php?uri=$1 last;
}3. 测试工具
bash
# 测试 NGINX 配置
nginx -t
# 重新加载配置
nginx -s reload
# 查看 NGINX 进程
ps aux | grep nginx
# 查看错误日志
tail -f /var/log/nginx/error.log4. 性能监控
nginx
# 启用状态页面
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}完整配置示例
WordPress 伪静态配置
nginx
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
# WordPress 伪静态规则
location / {
try_files $uri $uri/ /index.php?$args;
}
# 文章页面
location ~ ^/article/(\d+)$ {
rewrite ^/article/(\d+)$ /index.php?p=$1 last;
}
# 分类页面
location ~ ^/category/([a-zA-Z0-9-]+)$ {
rewrite ^/category/([a-zA-Z0-9-]+)$ /index.php?category_name=$1 last;
}
# 标签页面
location ~ ^/tag/([a-zA-Z0-9-]+)$ {
rewrite ^/tag/([a-zA-Z0-9-]+)$ /index.php?tag=$1 last;
}
# PHP 处理
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
}Laravel 伪静态配置
nginx
server {
listen 80;
server_name example.com;
root /var/www/html/public;
index index.php index.html;
# Laravel 伪静态规则
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# API 路由
location /api/ {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP 处理
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
}
}最佳实践
1. 规则顺序
- 将最具体的规则放在前面
- 将通用规则放在后面
- 避免规则冲突
2. 性能考虑
- 使用
try_files替代简单的重写 - 避免过多的正则表达式
- 合理使用缓存
3. 安全性
- 避免暴露内部文件路径
- 限制重写规则的作用范围
- 定期审查重写规则
4. 维护性
- 添加注释说明规则用途
- 使用有意义的变量名
- 定期测试重写规则