用 nginx 搭建纯单页应用服务

前言

有些朋友可能会有这个需求:想要部署单页面应用(Single-page application)到服务器上,但又不想为静态页面写一个(仅有 historyFallback 功能的)服务端。

确实,如果为静态页面再加一个服务端,有点重,性能也不如直接用 nginx 好。所以不如直接用 nginx 配置 historyFallback,轻量 && 简单。nginx

NGINX server 配置

nginx.conf 不用做什么特别的改动,所以这里就不介绍了。

以下规则有优先级,与 location 在配置文件中的顺序无关。
nginx location 匹配规则:

  1. =   普通字符精确匹配;
  2. ^~ 普通字符匹配,如果匹配,则不匹配别的选项,适合目录匹配;
  3. ~~* 正则匹配,后者不区分大小写;
  4. 普通字符逐字匹配。
仅一个单页(只有一个 html)的配置:
server {  
  listen          80;
  # 如果是直接暴露公网的,
  # server_name 写域名。
  # 因为我这里是 docker 环境,
  # 所以用 localhost。
  server_name     localhost;
  root            /usr/share/nginx/html;

  charset         utf-8;
  gzip_static     on;

  # static resources
  location ^~ /assets/ {
    expires       1M;
    access_log    off;
    add_header    Cache-Control "public";
  }

  # history fallback
  # GET /
  # GET /*
  location ~ ^/($|.*) {
    try_files     $uri /$1.html =404;
    default_type  'text/html; charset=utf-8';
  }

  # favicon
  location /favicon.ico {
    expires       1M;
    access_log    off;
    log_not_found off;
  }

  location / {
    index         index.html index.htm;
  }
}
多单页(多个 html)的配置:

比如要做一个管理后台,分为商家、管理员、员工端,之间业务和介面差距太大,而部分 JS 库与样式又共用,可以利用 webpack 做单页应用构建,配置方式见 multi-vue

# ...

# history fallback
# GET /任意非「/」字符
# GET /任意非「/」字符/
# GET /任意非「/」字符/*
location ~ ^/([^/]+)($|/$|/.*) {  
  try_files     $uri /$1.html =404;
  default_type  'text/html; charset=utf-8';
}

# ...

配置 historyFallback 的关键在于:
^/([^/]+)($|/$|/.*) 这个正则可以匹配以 /任意非「/」字符 开头,直接结尾、/ 结尾或 /*( * 代表任意字符)。

try_files 表示 nginx 在匹配到路径后,尝试访问第一个捕获组([^/]+)匹配字符组合的路径/$1.html(以上文件是绝对路径,因为配置了 root,因此根目录为指定值),=404 表示如果尝试访问不到文件一次以后,就会 404。

default_type 'text/html; charset=utf-8'; 是必须要加的
因为当你请求 /admin 时,nginx 不知道你要访问的文件类型是什么,会在响应头中加上默认的 Content-Type: application/octet-stream,浏览器看到这个头就直接开始下载文件,而不是以 html 类型解析并展示页面了。

注意:nginx location 正则匹配中,不像 JS 的正则,/ 不需要转义。

配置完成后,重启 nginx 就可以看到效果了。

参考

正在加载 Disqus 评论组件...