记一次 Nginx URI rewrite 优化

1. 背景

既上一篇文章记录了组内单页引擎升级路由为 History API 方式,考虑到不支持该方式的浏览器/WebView,需要多页降级。如果不对 Nginx 进行配置,就会出现404,因为多数通过pushState得到的 URL 并没有真实对应的资源。

2. URI 形式

采用 History API 方案的 URL 格式如下:

http[s]://hostname/resource/project/page[/view]?arg1=value1

其中 resource 为资源目录,该目录下放置各个不同的项目文件夹,每个项目对应一个 project 目录。一个 project 中可能会有多个单页应用,每个单页应用对应 URL 中的一个 page。一个单页应用下的不同视图分别对应一个 view。因为采用的单页引擎支持默认路由,所以 view 并非必需。

比如 A 项目下有一个 refund 的单页应用,对应的 HTML 资源为 refund.html,为了 URL 的美观,在 URL 中去掉 html 后缀名。refund 管理两个视图 detail 和 help,且默认视图为 detail。对应该情况,URI 有以下形式:

  • /resource/A/refund
  • /resource/A/refund/detail
  • /resource/A/refund/help

其中第1个 URI 和第2个相同,只是采用了默认视图。这三种 URL 都需要 map 到 refund.html 这个实际存在的 HTML 资源。除去 map HTML 资源,还需要 map 页面请求的各种 JS 和 image 资源。这两种资源都是在页面中通过相对地址引用的,对应的 URL 分别为:

  • ./page/refund.js
  • ./img/icon.png

这两种资源 URL 和上面的 URL 资源组合起来,一共有两种形式的 URL:

  • /resource/A/(page|img)/(refund.js|icon.png)
  • /resource/A/refund/(page|img)/(refund.js|icon.png)

3. 方案

3.1 初始

项目中的实际目录结构如下:

resource_static

--resource

--A

--refund.html

--page

--refund.js

--img

--icon.png

刚开始考虑针对两种类型的资源(HTML 和其他)分别做 rewrite,这样就得到下面的匹配规则:

# match img resource
location ~* ^/resource/([\w-.]+)/([\w-.]+)/(img|page)/(.*)$ {
  rewrite ^/resource/([\w-.]+)/([\w-.]+)/(img|page)/(.*)$ /resource/$1/$3/$4 last;
}
# match HTML resource
location ~* ^/resource/([\w-.]+)/.*$ {
  rewrite ^/resource/([\w-.]+)/([\w-.]+)$ /resource/$1/$2.html last;
  rewrite ^/resource/([\w-.]+)/([\w-.]+)/([\w-.]+)$ /resource/$1/$2.html last;
}
location / {
  root /resource_static/;
  index index.html index;
}

这就是最初也是根据上一步的 URI 分类得出的最直观版本。

3.2 优化

针对3.1中的方案,可以保证新 URI 中所有情况都可以找到对应的资源。但如果单页要引入项目下一个新文件夹中的资源,这时候就要修改上述第1条配置,添加对应目录名,这样扩展性就非常差。

换个角度考虑,其实 rewrite 的目的只是为了去掉由于 URI 中 view 对应的新增虚拟目录导致静态资源寻找多了 page 这一层。所以只要去掉包含这一层的 URL 即可。考虑采用 try_files 直接实现:

location ~* ^/resource/([\w-.]+)/([\w-.]+)(/.*)?$ {
  root /resource_static/;
  try_files /resource/$1/$2/$3 /resource/$1/$3 /resource/$1/$2 /resource/$1/$2.html =404;
}

上面这条配置中,location 后对应的 URI 可以匹配上述所有静态资源的 URI,并且没有写死任何目录名称。try_files 后第1、2个参数分别用来匹配默认视图和指定视图两种 URI 下的静态资源 URI,第3、4个参数用来匹配 HTML 或其它根目录资源,最后一个参数表示如果上述都不匹配,则直接返回404。这样。该条配置同样可以匹配目录下其它子目录或多级子目录的资源匹配。本质做的事情包括两点:针对目录下的资源请求,去掉 URI 中的 page 层;针对单页,添加 html 后缀名。

Nginx 中可以实现重定向的主要有3条指令:return,rewrite 和 try_files。关于3者分别的用法和他们之间的使用场景,可以先去google,本号后面的文章中也会陆续解释。还有一点要注意的是,在[]中写特殊字符,如.时,不需要转义。

4. 总结

综上,其实还是遇到问题不能只做到满足要求即可,而是要进一步深入看有么有更好的办法来解决当前解决方案中的一些瑕疵或者缺陷。借此机会,自己也对 Nginx 配置有了进一步了解。

原文发布于微信公众号 - nginx(nginx-study)

原文发表时间:2018-05-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏圣杰的专栏

ABP入门系列(20)——使用后台作业和工作者

源码路径:Github-LearningMpaAbp 1.引言 说到后台作业,你可能条件反射的想到BackgroundWorker,但后台作业并非是后台任务,...

8917
来自专栏草根专栏

Identity Server 4 - Hybrid Flow - Claims

前一篇 Identity Server 4 - Hybrid Flow - MVC客户端身份验证: https://www.cnblogs.com/cgzl/p...

1343
来自专栏淡定的博客

php之laravel学习常见错误1(连载中)

下面是我们整理的php的laravel学习的常见的错误以及解决的办法,我还会持续更新,请关注

2293
来自专栏与神兽党一起成长

我的解决stackoverflow无法正常登陆问题过程

1.从stackoverflow.com中点击login链接,查看network情况,可以发现几处错误。

1362
来自专栏晨星先生的自留地

finecmsV5.0.8写文件漏洞分析

4872
来自专栏王磊的博客

WebClient 访问间歇性返回403解决方案

说明:前段时间做的一个项目莫名的返回403的错误,这种情况也多大是程序员最不喜欢的了,没办法先来分析一下错误信息。之前的代码如下: WebClient webc...

46411
来自专栏张戈的专栏

启用WP Super Cache纯代码版本之后的一些优化措施

张戈博客在上个月 28 号启用了 WP Super Cache 代码版,几天下来,虽然小问题不断,但是总体感觉非常不错!不管是前台还是后台,速度都有质的提升,着...

3707
来自专栏Ryan Miao

sessionid如何产生?由谁产生?保存在哪里?

面试问道这个我居然不知道怎么回答,当然也是因为我确实没有研究过。下面就是百度了一篇文章后简单回答这个问题。 参考:http://www.cnblogs.com/...

5437
来自专栏代码世界

Cookie、Session登陆验证相关介绍和用法

一、Cookie和Session   首先、HTTP协议是无状态的;所谓的无状态是指每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系...

4497
来自专栏你不就像风一样

深入理解跨域SSO原理与技术

​ SSO英文全称Single Sign On,单点登录。SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登...

2111

扫码关注云+社区

领取腾讯云代金券