现代的浏览器已经支持HTML5的history.pushState,一种支持改变浏览器地址栏和历史而不发送实际服务器请求的技术。

记得以前的SPA(Single Page Application)应用是怎么做的么?在angular1里面,你会看到类似下面的地址:

http://localhost:8000/home/#/login

这里用了标记#来告诉浏览器,我这个不是真实的地址,不要试图去服务器上查这个请求。

现在我们不需要这么做了,使用HTML5支持的浏览器,直接地址栏里面看到的结果就是:

http://localhost:8000/home/login

是不是很赞?so far so good,直到你在你的nodejs服务器前面加了nginx。。。

一开始,看起来所有的东西都work,你的nginx配置可能如下:

server {

    listen       80 default_server;

    server_name  your.server.com;

    root /root/www;

    error_page 404 /404.html;

    error_page 500 502 503 504 /500.html;

    location / {
        index index.html;
    }
}

然而,当你打开页面并f5刷新的时候,你会得到一个大大的404错误。

为什么?因为nginx根据你的请求地址去找相应的页面了!!!结果当然是没找到!!!

通过一番google,你可能找到下面的解决方案,把所有未找到的页面重定向到index.html

server {
    listen       80 default_server;
    server_name  your.server.com;
    root /root/www;
    error_page 404 /404.html;
    error_page 500 502 503 504 /500.html;
    location / {
        index index.html;
        try_files $uri$args $uri$args/ $uri/ index.html =404;
    }
}

中间多出来的那段try-files告诉nginx,把所有找不到的请求都重定向发到index.html上去。

恩,你又试了试,看起来f5没有问题了。

但是,当你尝试输入一个不存在的地址http://localhost:8000/notexist的时候,你发现404页面没有出现,index.html还是被load了!!!(当然路由不存在,你会看到一个白的页面,但是所有index页面的代码还是被load了)

这是你要的结果么?可能有些网站希望这样,永远不会有40x和50x错误。但是如果我需要有404呢?看看刚才的配置,和404页面是有冲突的,你不能一边告诉nginx把所有找不到的页面重定向到index,又希望把不存在的页面跳转到404页面!

刚才配置里面最后的=404其实是永远到不了的,因为你的index.html页面一直存在!!!

怎么办?想了很久,我只能用一个workaround来部分解决这个,nignix的配置文件如下:

server {
    listen       80 default_server;
    server_name  your.server.com;
    root /root/www;
    error_page 404 /404.html;
    error_page 500 502 503 504 /500.html;
    location / {
        index app/index.html;
    }
    location /app {
        try_files $uri$args $uri$args/ $uri/ /app/index.html =404;
    }
}

然后移动并修改index.html,把里面的<base href="/">改成<base href="/app">

简单解释下,通过把index.html移动到app目录下,我给所有的虚拟请求建立了一个壳/app/**,所有app开头的请求,我都认为是angular2的虚拟请求,重定向到index去处理。其他的所有请求,如果不是一个真实存在的文件,都会跳到404页面。