WebSocket转发
之前已经解决了nginx
与uWSGI
对WebSocket
的转发问题,但其实还留着一些坑没有解决,就是在前端发送心跳包之后,后端收到之后会立即返回心跳包的内容heartBeat
,但是连接就会马上断开,然后重连.这个Bug找了好久,后来发现是前端的问题,因为后端对心跳包做出回复之后,前端的socket对象会触发onMessage
函数,但是之前的onMessage
函数写得有点问题,接收到之后会对消息进行反序列化,本来是想对另外一种消息进行反序列化,这样是不会出错的,但是接收到心跳包的回复后也会触发这个函数,报错,就触发了onError
函数,然后重新连接.
将函数改过来,加上1
2
3
4
5
6
7
8try {
if (msg.data === 'heartBeat') {
this.reset();
return;
}
} catch (e) {
console.log(e);
}
但是还是没有解决问题,而是直接收不到后端的心跳消息了
由于测试的时候就算不走nginx
,也是无法正常回复,于是查看uWSGI
的日志,发现有几行是这样的:1
2
3
4Thu Apr 23 13:47:45 2020 - ASYNC call without async mode !!!
Thu Apr 23 13:48:00 2020 - ASYNC call without async mode !!!
Thu Apr 23 13:48:15 2020 - ASYNC call without async mode !!!
Thu Apr 23 13:48:27 2020 - ASYNC call without async mode !!!
无异步模式的异步调用.
推断应该是建立连接之后,根据代码段的执行顺序,接收到心跳包之后,再回复(由于现在已经解决了问题,所以记不太清之前到底能不能回复了),然后代码执行结束,由于uWSGI
并非是异步模式,所以连接自动断开了,然后前端再次重连…
到uWSGI
官网上查看异步开启方案,官网上是这样写的:
它们简单实现了协程(coroutine)/绿色线程(green thread)技术。它们并无事件引擎,因此,你必须使用由uWSGI提供的。一个事件引擎通常是一个为平台无关的非阻塞I/O(libevent, libev, libuv等等)导出基元的库。使用 —async
选项启用uWSGI事件引擎。目前,uWSGI发布版本包含了以下挂起/恢复引擎:
- uGreen - Unbit的绿色线程实现 (基于swapcontext())
- Greenlet - Python greenlet模块
- Stackless - Stackless Python
- Fiber - Ruby 1.9 fibers
所谓绿色线程(Green threads),则是程序里面的线程不会真正映射到操作系统的线程,而是由语言运行平台自身来调度。而操作系统线程(Native Thread)的意思就是,程序里面的线程会真正映射到操作系统的线程,线程的运行和调度都是由操作系统控制的.
绿色线程实际上是一种模拟的线程,优点是完全由语言运行平台管理,所以易于创建和销毁.
用uwsgi --ini uwsgi.ini --async 100 --ugreen
开启异步,WebSocket
连接成功,并且可以成功发送和接收消息,不会断开.
nginx代理
前后端分离代理
之前的代理方式是前端将将代码编译进/dist
后,django
设置里将静态文件路径改成前端编译后的/dist
文件夹,然后python manage.py collectstatic
,将静态文件收集到根目录下面的/static
文件夹,然后用nginx
代理后端应用,这样用vue.js
写的组件走的还是index.html
的路由,而这个路由是由vue.router
指定的,所以用起来和写前端的时候没有区别,并且可以搜集admin
的静态文件.
这种代理方式其实还是和后端应用同端口的,不会产生跨域问题,前后端并没有分别代理.并且前后端之间的请求走的都是公网,而不是直接内部转发.
而前后端分别代理,需要重新配置nginx
的.conf
文件.
对前端:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23server {
listen 80;
server_name 公网ip或者域名; # 域名
access_log /var/log/nginx/access.log;
charset utf-8;
gzip on;
gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text>
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location / {
root /*/*/*/dist/;
try_files $uri $uri/ /index.html;
}
location /message/api/ {
proxy_pass http://127.0.0.1:82/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
对后端:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25server {
listen 82;
server_name 127.0.0.1; # 域名
access_log /var/log/nginx/access.log;
charset utf-8;
gzip on;
gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/js>
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# 指定项目路径uwsgi
location / {
include uwsgi_params;
uwsgi_connect_timeout 30;
uwsgi_pass unix:/*/*/*/uwsgi.sock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 指定静态文件路径
location /static/ {
alias /*/*/*/static/;
index index.html index.htm;
}
}
分析前端配置文件,在80
端口,由nginx
代理前端的静态文件,并且将/message/api/
路径指向本机的82
端口,分析后端配置文件,监听本机的82
端口,将默认路径指向uwsgi.sock
文件,与uWSGI
建立关联,将动态请求转发给uWSGI
,下面的location /static/
其实可以去掉,这是直接访问82
端口的时候也能正常访问设置的.
按上述配置,前后端就分离代理了,服务器安全组关闭82
端口,只开放80
端口,后端应用跑在的本机的8000
端口,而nginx
监听82
端口,前端在80
端口接收请求,然后对动态请求进行分发.
这样部署的好处是更加安全了,不会暴露过多端口,并且前后端解耦,但是一个缺点就是无法使用django
的admin
了,因为admin
是由后端渲染的,这样部署就是后端只提供接口,而不参与渲染页面.
同端口代理不同端口
上面是在80
端口前后端分离部署的方式部署了一个项目,但是如果想要多个项目都部署到80
端口,配置就要发生改变了.
首先在80
端口,加上配置项:1
2
3
4
5
location /hospital/ {
proxy_pass http://127.0.0.1:81/;
proxy_http_version 1.1;
}
这样配置就将路径为hospital
的请求转发到本机的81端口.
然后新建*_front.conf
文件,写上配置项:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23server {
listen 81;
server_name 127.0.0.1; # 域名
access_log /var/log/nginx/access.log;
charset utf-8;
gzip on;
gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/js>
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# 指定项目路径uwsgi
location / {
root /*/*/*/dist/;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:83/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
然后新建*_backend.conf
文件,写上配置项:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18server {
listen 83;
server_name 127.0.0.1; # 域名
access_log /var/log/nginx/access.log;
charset utf-8;
gzip on;
gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/js>
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# 指定项目路径uwsgi
location / {
include uwsgi_params;
uwsgi_connect_timeout 30;
uwsgi_pass unix:/*/*/*/uwsgi.sock;
proxy_http_version 1.1;
}
}
完整的请求流程是,前端发送请求到80端口,路径为/hospital/
,然后nginx
将请求转发到本机的81
端口,81
端口收到后返回静态文件,然后将动态请求转发给/api/
接口,即83
端口,83
端口收到后将请求转发给uWSGI
处理,然后将结果渲染到页面.
其实可以写得更简单一点,不过我觉得这样配置更加清晰一点,管理起来也容易.
不过还是上面的缺点,不能访问django
的admin
..
踩了好多坑,感受到自己深深的菜….
- 本文标题:nginx与uWSGI踩坑记录
- 本文作者:Kale
- 创建时间:2020-04-23 13:16:46
- 本文链接:https://kalew515.com/2020/04/23/nginx与uWSGI踩坑记录/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!