找回密码
 立即注册
首页 业界区 业界 apisix~proxy-rewrite 的 regex_uri 深度解析

apisix~proxy-rewrite 的 regex_uri 深度解析

奚娅琼 2025-9-26 11:03:05
APISIX 路由正则与 proxy-rewrite 的 regex_uri 深度解析

在 APISIX 中,proxy-rewrite 插件的 regex_uri 功能是实现复杂路由重写的核心工具。下面我将全面总结各种转发场景的使用方法和技巧。
regex_uri 基础语法
  1. "regex_uri": ["匹配正则", "替换模板"]
复制代码

  • 匹配正则:PCRE 格式的正则表达式
  • 替换模板:使用 $1, $2 等引用捕获组
常见转发场景总结

场景 1:简单前缀替换
  1. "regex_uri": ["^/api/v1/(.*)", "/backend/$1"]
复制代码
请求转换:

  • /api/v1/users → /backend/users
  • /api/v1/products/123 → /backend/products/123
场景 2:多段路径重组
  1. "regex_uri": ["^/user/([^/]+)/profile/(.*)", "/profile/$1/$2"]
复制代码
请求转换:

  • /user/john/profile/settings → /profile/john/settings
  • /user/mary/profile/preferences → /profile/mary/preferences
场景 3:版本号升级
  1. "regex_uri": ["^/v1/(.*)", "/v2/$1"]
复制代码
请求转换:

  • /v1/orders → /v2/orders
  • /v1/inventory/items → /v2/inventory/items
场景 4:路径参数提取
  1. "regex_uri": ["^/product/(\\d+)/detail", "/items/$1"]
复制代码
请求转换:

  • /product/123/detail → /items/123
  • /product/456/detail → /items/456
场景 5:多条件组合匹配
  1. "regex_uri": ["^/(user|product)/(create|delete)/([a-z]+)", "/action/$2/$1/$3"]
复制代码
请求转换:

  • /user/create/account → /action/create/user/account
  • /product/delete/item → /action/delete/product/item
场景 6:保留查询参数
  1. "regex_uri": ["^/search/(.*)", "/query/$1"]
复制代码
请求转换:

  • /search/books?category=sci-fi → /query/books?category=sci-fi
  • /search/movies?year=2023 → /query/movies?year=2023
场景 7:路径规范化
  1. "regex_uri": ["^/([a-z]{2})/([a-z]+)/?$", "/$2/$1"]
复制代码
请求转换:

  • /en/home → /home/en
  • /es/about → /about/es
场景 8:复杂重写模式
  1. "regex_uri": ["^/(?:api|service)/v(\\d+)/(.*)", "/v$1/$2"]
复制代码
请求转换:

  • /api/v2/users → /v2/users
  • /service/v3/products → /v3/products
高级应用场景

场景 9:条件重写(配合 vars)
  1. "plugins": {
  2.     "proxy-rewrite": {
  3.         "regex_uri": ["^/user/(.*)", "/$1"],
  4.         "vars": [
  5.             ["http_x_api_version", "==", "v2"]
  6.         ]
  7.     }
  8. }
复制代码
仅当请求头 X-API-Version: v2 时生效
场景 10:多重正则组合
  1. "plugins": [
  2.     {
  3.         "proxy-rewrite": {
  4.             "regex_uri": ["^/api/", "/"]
  5.         }
  6.     },
  7.     {
  8.         "proxy-rewrite": {
  9.             "regex_uri": ["^/v1/", "/v2/"]
  10.         }
  11.     }
  12. ]
复制代码
分阶段重写:

  • /api/v1/users → /v1/users
  • /v1/users → /v2/users
场景 11:正则与直接 URI 重写结合
  1. "plugins": {
  2.     "proxy-rewrite": {
  3.         "uri": "/new-base",
  4.         "regex_uri": ["^/old/(.*)", "/$1"]
  5.     }
  6. }
复制代码
组合效果:

  • /old/path → /new-base/path
  • /other → /new-base/other
性能优化技巧


  • 非捕获组优化:使用 (? 代替 () 避免不必要的捕获
    1. "regex_uri": ["^/(?:api|service)/v(\\d+)/(.*)", "/v$1/$2"]
    复制代码
  • 避免贪婪匹配:使用 .*? 代替 .* 防止过度匹配
    1. "regex_uri": ["^/category/(.*?)/(detail)", "/$2/$1"]
    复制代码
  • 精确锚定:使用 ^ 和 $ 限定匹配范围
    1. "regex_uri": ["^/exact/path$", "/new/exact"]
    复制代码
调试与测试方法

1. 使用 curl 测试
  1. curl "http://127.0.0.1:9080/apisix/admin/plugin_metadata/proxy-rewrite" \
  2. -H "X-API-KEY: your-admin-key" -X PUT -d '
  3. {
  4.     "regex_uri_debug": true
  5. }'
复制代码
2. 日志分析

在 error.log 中查看匹配详情:
  1. 2023/10/15 14:30:22 [debug] regex_uri match: pattern=^/api/(.*), uri=/api/v1/users, matches=1
  2. 2023/10/15 14:30:22 [debug] regex_uri replace: /api/v1/users -> /v1/users
复制代码
3. 单元测试(Lua)
  1. local rewrite = require("apisix.plugins.proxy-rewrite")
  2. local ctx = {var = {uri = "/old/path"}}
  3. rewrite.rewrite({regex_uri = {"^/old/(.*)", "/new/$1"}}, ctx)
  4. ngx.say(ctx.var.uri) -- 输出: /new/path
复制代码
常见问题解决方案

问题 1:正则不匹配

解决方案

  • 使用在线正则测试器验证(如 regex101.com)
  • 添加调试日志 regex_uri_debug: true
  • 简化正则表达式,分步测试
问题 2:特殊字符转义

正确写法
  1. "regex_uri": ["^/search\\?q=(.+)", "/query/$1"]
复制代码
问题 3:保留原始路径
  1. "regex_uri": ["", "$0"] -- 保留完整原始路径
复制代码
问题 4:大小写敏感问题
  1. "regex_uri": ["(?i)^/api/(.*)", "/$1"] -- 忽略大小写
复制代码
最佳实践


  • 路径标准化:在网关层统一路径格式
    1. "regex_uri": ["^/[A-Z]+/(.*)", "/${lower($1)}"]
    复制代码
  • 版本控制:无缝升级 API 版本
    1. "regex_uri": ["^/v1/(.*)", "/v2/$1"]
    复制代码
  • 多租户支持
    1. "regex_uri": ["^/([a-z0-9]+)/api/(.*)", "/tenants/$1/$2"]
    复制代码
  • A/B 测试路由
    1. "regex_uri": ["^/service/(.*)", "/service-v2/$1"],
    2. "vars": [["http_x_test_group", "==", "B"]]
    复制代码
  • 协议升级重定向
    1. "plugins": {
    2.     "proxy-rewrite": {
    3.         "regex_uri": ["^(.*)", "https://new-domain.com$1"],
    4.         "scheme": "https"
    5.     }
    6. }
    复制代码
性能对比表

方法复杂度适用场景性能影响regex_uri中-高复杂路径转换中(PCRE 编译)uri 直接替换低简单前缀修改低多插件组合高分阶段处理中-高Nginx 原生 rewrite中深度定制最低
建议:简单场景使用 uri 直接替换,复杂场景使用 regex_uri
自己项目中的使用

1. 静态改写,不需要正则
  1. "proxy-rewrite": {
  2.       "uri": "/auth/realms/xx/protocol/openid-connect/token/introspect"
  3.   }
复制代码
2. 表达url一级路径的文件名,扩展名是.txt,例如:http://www.sina.com/1.txt
  1. "proxy-rewrite": {
  2.       "regex_uri": [
  3.         "^/([^/]+\\.txt)$",
  4.         "/auth/$1"
  5.       ]
  6.     }
复制代码
3. 按前缀进行替换
  1. "proxy-rewrite": {
  2.     "regex_uri": [
  3.         "^/user-xx(/.*)",
  4.         "$1"
  5.       ]
  6.     }
复制代码
4. 以某个前缀开头的,在转发时,在前缀前面添加固定字符,下面添加了apim-es到apim-admin的前面
  1. "proxy-rewrite": {
  2.      "regex_uri": [
  3.         ""^/apim-admin/(.*)"",
  4.         "/apim-es/$1"
  5.       ]
  6.     }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册