Nginx 部署同域名下 Laravel/Lumen 和 react 完全前后端分离

重构一个项目,本来用的是 Laravel 全栈式开发,现重构成 react 前端和 Laravel 后端的完全分离的方式,使用 Nginx 部署在同域名下。

这个过程也是踩了些坑,不过最后配成功了。

测试环境

  • React 16.4.1
  • Laravel 5.6
  • Nginx 1.13

配置 NGINX

先看看完整的 NGINX 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
server {
listen 80;
server_name example.com;

#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;

root /path/to/frontend/build;
index index.html index.htm;

location / {
try_files $uri $uri/ /index.html;
}

location ^~ /api {
index index.php index.html index.htm;

alias /path/to/laravel/public;
try_files $uri $uri/ @api;

location ~ \.php {
fastcgi_pass 172.40.2.2:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME /path/to/laravel/public/index.php;
fastcgi_connect_timeout 180;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
client_body_buffer_size 1024k;
include fastcgi_params;
}
}

location @api {
rewrite /api/(.*)$ /api/index.php/$1 last;
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}

# serve static files directly
location ~* \.(?:bmp|ico|css|js|jpeg|jpg|png|tiff|svg|woff)$ {
access_log off;
log_not_found off;
expires 30d;
}
}

可以看到,主要把二级目录下的 Laravel 工程配置正确就可以了。

但是,坑来了!
不要以为就这样完事了。 当你访问 http://example.com/api,也就是后端的时候,第一次是没问题的,第二次会显示前端 index.html 的界面。

研究了好久,发现是一个叫 Service Worker 的东西惹的祸。详细的介绍可以看这篇文章《深入了解 Service Worker,看这篇就够了》。

是这个货影响了浏览器,第二次请求 URL 的时候,直接使用了本地的缓存,但是本地并没有 Nginx 端的 API 配置,所以显示 index.html 的内容。

当前我用的这个版本的 React 是默认自带并启用这个服务的,网上也有人抱怨为什么要开启:《Why was service worker merged into create react app?

看完上面两个参考链接,可以得出初步解决方案。要么在 Service Worker 的 js 出加入 api 的 url 过滤规则,要么就干脆关了。

方法一不是很难,找到 registerServiceWorker.js 编辑下就可以了,如:《Setting service worker to exclude certain urls only

方法二更干脆,就是把这个功能关了。编辑 index.js,把
// import registerServiceWorker from './registerServiceWorker';
// registerServiceWorker();
两行都注释了。