从一台 nginx 服务器提供多个版本的多个单页应用程序?
Serve multiple versions of multiple Single Page Applications from one nginx server?
我需要从一台服务器提供多个单页应用程序 (SPA) 的多个版本。
如果 URL 指定了服务器上不存在的版本,我想改为提供后备版本。
有些版本实际上是其他版本的符号链接。
# /var/www/apps/example-app
0.1.0
0.1.1
0.1.2
fooversion -> /var/www/apps/example-spa/0.1.2
latest -> /var/www/apps/example-spa/0.1.1
版本 latest
是我想用作后备的版本。
所有 SPA 都有一个 index.html
文件。
我特别不想提供来自不同版本的混合文件。如果服务器上存在某个版本,则应从该文件夹提供对该版本的所有请求。
# excerpt from nginx config
...
location ~ ^/apps/(?<appname>.+?)/(?<appversion>.+?)/(?<suffix>.*)
{
# 'latest' is the name of the folder with the fallback version
set $effectiveversion latest;
# NOTE: file check does not take into account `root` directive, use full path
if (-f /var/www/apps/$appname/$appversion/index.html) {
set $effectiveversion $appversion;
}
# try path, then force to SPA index
try_files /apps/$appname/$effectiveversion/$suffix /apps/$appname/$effectiveversion/index.html;
}
# catch requests that end without a trailing slash
location ~ ^/apps/(?<appname>.+?)/(?<appversion>[^\/]+)$
{
try_files /NONEXISTENTFILE /apps/$appname/$appversion/;
}
...
我知道 if
可能是个问题,考虑到它在 nginx 配置中的声誉。
(注意:后缀是指版本之后的斜杠后的任何内容,因此 /file.extension
和 /some/folder/that/does/notexist/
都是后缀。如果文件存在,则应提供文件,并且所有子文件夹都应提供服务版本的 index.html
.
此代码目前适用于以下 URLs:
https://example.com/apps/bar-app/nonexistentversion/nonexistentsuffix
https://example.com/apps/bar-app/nonexistentversion/nonexistentsuffix/
https://example.com/apps/bar-app/nonexistentversion
https://example.com/apps/bar-app/nonexistentversion/
https://example.com/apps/bar-app/nonexistentversion/existentsuffix
https://example.com/apps/bar-app/existentversion/existentsuffix
https://example.com/apps/bar-app/existentversion/
https://example.com/apps/bar-app/existentversion
但它不适用于这些:
https://example.com/apps/bar-app/existentversion/nonexistentsuffix
https://example.com/apps/bar-app/existentversion/nonexistentsuffix/
目前这最后两个 return 404。
==> /var/log/nginx/error.log <==
2020/06/03 14:23:15 [error] 7100#7100: *1289803 open() "/var/www/apps/example-app/fooversion/somefrontendroute" failed (2: No such file or directory), client: ..., server: , request: "GET /apps/example-app/fooversion/somefrontendroute HTTP/1.1", host: "static.bar.com", referrer: ...
==> /var/log/nginx/access.log <==
[03/Jun/2020:14:23:15 +1000] ... - "GET /apps/example-app/fooversion/somefrontendroute HTTP/1.1" 404 209 - 0.000 - - - 1591158195.572 -"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "..., ..."
有没有办法涵盖最后这几个案例?或者甚至是处理整个问题的更简洁的方法?
工作解决方案:
(99% 是 Richard Smith 的回答,我刚刚添加了重写)
# cover case where version has no trailing `/`
rewrite ^/apps/([^/]+?)/([^/]+)$ /apps///;
location ~ ^/apps/(?<app>.+?)/(?<version>.+?)/(?<rest>.*)$
{
try_files
/apps/$app/$version/$rest
/apps/$app/$version/index.html
/apps/$app/latest/$rest
/apps/$app/latest/index.html
;
}
如果 URI 不存在,它将提供索引而不是 404。这对我来说是可以接受的
您可能可以删除 if
块,因为 try_files
指令实际上与 if (-f
.
相同
try_files
语句的最后一个参数不是 file 项。通过在语句末尾添加 =404
,您的最后一个参数将成为常规 file 术语,这可能是您出现问题的根本原因。
有关详细信息,请参阅 this document。
例如:
location ~ ^/apps/(?<appname>.+?)/(?<appversion>.+?)/(?<suffix>.*)$
{
try_files
$uri
/apps/$appname/$appversion/index.html
/apps/$appname/latest/$suffix
/apps/$appname/latest/index.html
=404
;
}
我需要从一台服务器提供多个单页应用程序 (SPA) 的多个版本。
如果 URL 指定了服务器上不存在的版本,我想改为提供后备版本。
有些版本实际上是其他版本的符号链接。
# /var/www/apps/example-app
0.1.0
0.1.1
0.1.2
fooversion -> /var/www/apps/example-spa/0.1.2
latest -> /var/www/apps/example-spa/0.1.1
版本 latest
是我想用作后备的版本。
所有 SPA 都有一个 index.html
文件。
我特别不想提供来自不同版本的混合文件。如果服务器上存在某个版本,则应从该文件夹提供对该版本的所有请求。
# excerpt from nginx config
...
location ~ ^/apps/(?<appname>.+?)/(?<appversion>.+?)/(?<suffix>.*)
{
# 'latest' is the name of the folder with the fallback version
set $effectiveversion latest;
# NOTE: file check does not take into account `root` directive, use full path
if (-f /var/www/apps/$appname/$appversion/index.html) {
set $effectiveversion $appversion;
}
# try path, then force to SPA index
try_files /apps/$appname/$effectiveversion/$suffix /apps/$appname/$effectiveversion/index.html;
}
# catch requests that end without a trailing slash
location ~ ^/apps/(?<appname>.+?)/(?<appversion>[^\/]+)$
{
try_files /NONEXISTENTFILE /apps/$appname/$appversion/;
}
...
我知道 if
可能是个问题,考虑到它在 nginx 配置中的声誉。
(注意:后缀是指版本之后的斜杠后的任何内容,因此 /file.extension
和 /some/folder/that/does/notexist/
都是后缀。如果文件存在,则应提供文件,并且所有子文件夹都应提供服务版本的 index.html
.
此代码目前适用于以下 URLs:
https://example.com/apps/bar-app/nonexistentversion/nonexistentsuffix
https://example.com/apps/bar-app/nonexistentversion/nonexistentsuffix/
https://example.com/apps/bar-app/nonexistentversion
https://example.com/apps/bar-app/nonexistentversion/
https://example.com/apps/bar-app/nonexistentversion/existentsuffix
https://example.com/apps/bar-app/existentversion/existentsuffix
https://example.com/apps/bar-app/existentversion/
https://example.com/apps/bar-app/existentversion
但它不适用于这些:
https://example.com/apps/bar-app/existentversion/nonexistentsuffix
https://example.com/apps/bar-app/existentversion/nonexistentsuffix/
目前这最后两个 return 404。
==> /var/log/nginx/error.log <==
2020/06/03 14:23:15 [error] 7100#7100: *1289803 open() "/var/www/apps/example-app/fooversion/somefrontendroute" failed (2: No such file or directory), client: ..., server: , request: "GET /apps/example-app/fooversion/somefrontendroute HTTP/1.1", host: "static.bar.com", referrer: ...
==> /var/log/nginx/access.log <==
[03/Jun/2020:14:23:15 +1000] ... - "GET /apps/example-app/fooversion/somefrontendroute HTTP/1.1" 404 209 - 0.000 - - - 1591158195.572 -"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "..., ..."
有没有办法涵盖最后这几个案例?或者甚至是处理整个问题的更简洁的方法?
工作解决方案:
(99% 是 Richard Smith 的回答,我刚刚添加了重写)
# cover case where version has no trailing `/`
rewrite ^/apps/([^/]+?)/([^/]+)$ /apps///;
location ~ ^/apps/(?<app>.+?)/(?<version>.+?)/(?<rest>.*)$
{
try_files
/apps/$app/$version/$rest
/apps/$app/$version/index.html
/apps/$app/latest/$rest
/apps/$app/latest/index.html
;
}
如果 URI 不存在,它将提供索引而不是 404。这对我来说是可以接受的
您可能可以删除 if
块,因为 try_files
指令实际上与 if (-f
.
try_files
语句的最后一个参数不是 file 项。通过在语句末尾添加 =404
,您的最后一个参数将成为常规 file 术语,这可能是您出现问题的根本原因。
有关详细信息,请参阅 this document。
例如:
location ~ ^/apps/(?<appname>.+?)/(?<appversion>.+?)/(?<suffix>.*)$
{
try_files
$uri
/apps/$appname/$appversion/index.html
/apps/$appname/latest/$suffix
/apps/$appname/latest/index.html
=404
;
}