一、针对 browser history 模式下服务器配置

browser history 是React Router 官方推荐的 history。它使用浏览器中的 History API 处理 URL ,会创建一个像 example.com/some/path 这样真实的 URL 。

服务器配置
服务器需要做好处理 URL 的准备。处理最初的 / 这样的请求应该没问题,但当用户来回跳转并在 /accounts/123 页面刷新时,服务器就会收到来自 /accounts/123 的请求,由于服务端无法查找到该资源,便会报 404 错误。

针对上述情况,一个 express 的服务端应用配置可能像这样的:

  1. const express = require('express')
  2. const path = require('path')
  3. const port = process.env.PORT || 8080
  4. const app = express()
  5. // 通常用于加载静态资源
  6. app.use(express.static(__dirname + '/public'))
  7. // 在你应用 JavaScript 文件中包含了一个 script 标签
  8. // 的 index.html 中处理任何一个 route
  9. app.get('*', function (request, response){
  10. response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
  11. })
  12. app.listen(port)
  13. console.log("server started on port " + port)

如果你的服务器是 nginx,则使用 try_files 指令:

  1. server {
  2. ...
  3. location / {
  4. try_files $uri /index.html
  5. }
  6. }

当在服务器上找不到其他文件时,这可以让 nginx 服务器提供静态文件服务并指向index.html 文件。

注:

上述情况通常发生在browserHistory模式下,hashHistory模式下则不存在上述问题。

二、Nginx 配置样例

以下是将前端 SPA 应用私有化部署到他人服务器上的 Nginx 配置样例。

  1. # 指定用户:他人分配的账号
  2. user shimu;
  3. worker_processes auto;
  4. # 指定log输出目录
  5. error_log /home/shimu/nginx/error.log;
  6. pid /run/nginx.pid;
  7. # Load dynamic modules.
  8. include /usr/share/nginx/modules/*.conf;
  9. events {
  10. worker_connections 1024;
  11. }
  12. http {
  13. log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  14. '$status $body_bytes_sent "$http_referer" '
  15. '"$http_user_agent" "$http_x_forwarded_for"';
  16. access_log /var/log/nginx/access.log main;
  17. sendfile on;
  18. tcp_nopush on;
  19. tcp_nodelay on;
  20. keepalive_timeout 65;
  21. types_hash_max_size 2048;
  22. include /etc/nginx/mime.types;
  23. default_type application/octet-stream;
  24. # Load modular configuration files from the /etc/nginx/conf.d directory.
  25. # See http://nginx.org/en/docs/ngx_core_module.html#include
  26. # for more information.
  27. include /etc/nginx/conf.d/*.conf;
  28. server {
  29. listen 80 default_server;
  30. listen [::]:80 default_server;
  31. server_name _;
  32. # 指定文件路径
  33. root /home/shimu/fengrong/web/dist;
  34. # Load configuration files for the default server block.
  35. include /etc/nginx/default.d/*.conf;
  36. # 若当前文件不存在,则进行重定向。
  37. location / {
  38. if (!-e $request_filename) {
  39. rewrite ^/(.*) /index.html last;
  40. break;
  41. }
  42. }
  43. location /api {
  44. proxy_pass http://127.0.0.1:8800/api;
  45. proxy_set_header Host $host;
  46. }
  47. error_page 404 /404.html;
  48. location = /40x.html {
  49. }
  50. error_page 500 502 503 504 /50x.html;
  51. location = /50x.html {
  52. }
  53. }
  54. }

其中:

  • user:nginx 运行后可以指定用户,比如说一个静态网页服务器的文件目录的不同的用户有不同的访问权限,使用 nginx 指定用户就可以有权限对此目录读写,详见链接
  • root:root 是 web 根目录,建议使用绝对路径。相对路径受制于nginx的工作目录,存在不确定性;
  • $request_filename:当前请求的文件路径,由 root 或 alias 指令与URI请求生成;
  • -e和!-e:用来判断是否存在文件或目录;
  • rewrite:rewrite是 nginx 中的重定向指令。^/(.*)是重定向规则,/index.html重定向路径。

三、解决 Nginx 的 “403 Forbidden” 报错

引起 “403 Forbidden” 有两种原因,一是缺少索引文件,二是权限问题。

1) 缺少 index.html

  1. server {
  2. listen 80;
  3. server_name localhost;
  4. index index.html;
  5. root /home/shimu/web;

如果在/home/shimu/web下面没有index.html,此时访问域名(www.example.com) 会找不到文件, Nginx 便会报“403 Forbidden”错误。

针对这一问题,首先查看下 root 是否使用的是绝对路径。不要使用相对路径,因为相对路径受制于Nginx的工作目录,存在不确定性。

2) 权限问题
因为权限问题引起的 403。通常我们会将 web 目录放在用户的所属目录下面,nginx 的启动用户默认是 nginx 的,所以对目录根本没有读的权限,这样就会报403错误了。这个时候,把web目录的权限改大,或者是把nginx的启动用户改成目录的所属用户,重起一下就能解决。

  1. # nginx的默认启动用户是nginx
  2. # user nginx
  3. # web 目录下所在的用户
  4. user shimu;