最近的目标是用 Python 来搭建一个可访问的热门网站热榜数据 API,目前已经实现了:
本篇是最后一步,要完善 API 数据的抓取和通过域名可以拿到 API 数据。要实现此目的:
环境:本地电脑时 macOS 系统;云服务器是 CentOS 7; Django 是 Python 3.7.5
一个web服务器面对的是外部世界。它能直接从文件系统提供文件 (HTML, 图像, CSS等等)。然而,它无法 直接与Django应用通信;它需要借助一些工具的帮助,这些东西会运行运用,接收来自web客户端(例如浏览器)的请求,然后返回响应。
一个Web服务器网关接口(Web Server Gateway Interface) - WSGI - 就是干这活的。 WSGI 是一种Python标准。
uWSGI是一种WSGI实现。在这个教程中,我们将设置uWSGI,让它创建一个Unix socket,并且通过WSGI协议提供响应到web服务器。最后,我们完整的组件栈看起来将是这样的:
the web client <-> the web server <-> the socket <-> uwsgi <-> Django
以上关于 uWSGI 的概念来自于 uWSGI 相关的文档,我们暂且理解为 uWSGI 是用来将 Django 项目与 socket 通讯的中介。我们主要来实现相关的安装部署。
基于之前实现的将 Django 项目部署到了服务器上,我们连到服务器,虚拟环境下进入自己的项目目录:
sudo ssh 175.24.134.227
# 输入密码连接到服务器
[root@VM_0_11_centos ~]# cd tedxapi/
[root@VM_0_11_centos tedxapi]# ls
myapi myvenv
[root@VM_0_11_centos tedxapi]# source myvenv/bin/activate
(myvenv) [root@VM_0_11_centos tedxapi]# cd myapi/
(myvenv) [root@VM_0_11_centos myapi]# pip install uwsgi
之前我们运行 Django 项目是靠 manage.py 的 runserver 命令,配置了 uwsgi 之后,就要通过 uwsgi 来运行 Django 项目了。因为要启动项目时需要配置些参数,为了方便将参数定义在 ini 格式的文件中。保持终端路径不变,执行以下命令新建 myapi_uwsgi.ini 文件并配置相关参数。
(myvenv) [root@VM_0_11_centos myapi]# vim myapi_uwsgi.ini
执行完上面这个 vim 命令后,终端会进入该文件的编辑界面,这时按下字母 i 键进入插入模式,就可以在文件中编辑内容了,复制如下配置贴到文件中,部分数据要根据不同项目做调整:
# myapi_uwsgi.ini file
[uwsgi]
# Django-related settings
http =:8000
# the base directory (full path)
chdir = /root/tedxapi/myapi
# Django s wsgi file
module = myapi.wsgi
# the virtualenv full path
home = /root/tedxapi/myvenv
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 2
# the socket (use the full path to be safe
socket = /root/tedxapi/myapi/mysite.sock
# ... with appropriate permissions - may be needed
chmod-socket = 666
# clear environment on exit
vacuum = true
daemonize = /root/tedxapi/myapi/uwsgi_myapi.log
safe-pidfile = /root/tedxapi/myapi/pid_myapi.pid
配置中赋值给 socket 的 mysite.sock 文件是 uwsgi --ini 运行后所配的 socket 位置,之后 nginx 会通过该 sock 文件连接到该 socket 位置。
demonize 对应的 uwsgi_myapi.log 用来记录输出的日志。
safe-pidfile 对应的 pid_myapi.pid 用来记录uwsgi 进程的内存ID,更改 uwsgi 或 Django 更新配置后可以用记录的 ID 重新启动 uwsgi。如果不配置该文件,只能通过将 uwsgi 进程全部杀死再重启。
复制并编辑完上述内容后,先按 Esc 键退出编辑模式,然后输入 :wq 再回车,以保存并退出该 vim 模式。返回到终端命令界面后,可以 ls 指令看到路径下多了个 myapi_uwsgi.ini 文件:
(myvenv) [root@VM_0_11_centos myapi]# ls
db.sqlite3 get_website.py hotlist __init__.py manage.py myapi myapi_uwsgi.ini
执行 uwsgi --ini myapi_uwsgi.ini 的命令:
(myvenv) [root@VM_0_11_centos myapi]# uwsgi --ini myapi_uwsgi.ini
[uWSGI] getting INI configuration from myapi_uwsgi.ini
(myvenv) [root@VM_0_11_centos myapi]# ls
db.sqlite3 hotlist manage.py myapi_uwsgi.ini pid_myapi.pid
get_website.py __init__.py myapi mysite.sock uwsgi_myapi.log
可以看到刚提过的 mysite.sock、myapi.log 及 myapi.pid 等文件也都出现在了路径内。
该文件会在 nginx 配置时用到,我们可以通过 https://github.com/nginx/nginx/blob/master/conf/uwsgi_params
下载后上传至服务器,当然更简便的方式是用 vim 指令新建并编辑其中内容:
(myvenv) [root@VM_0_11_centos myapi]# vim uwsgi_params
在弹出的 vim 编辑区内,先按 i 键进入插入模式,将下列内容复制粘贴:
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
第一行是空着的,不知道去掉会不会影响,但先保持和 GitHub 上的这种一致吧。
编辑完毕,按 Esc,输入 :wq 保存并退出 vim 编辑模式,可以看到路径内多了 uwsgi_params 文件:
(myvenv) [root@VM_0_11_centos myapi]# ls
db.sqlite3 hotlist manage.py myapi_uwsgi.ini pid_myapi.pid uwsgi_params
get_website.py __init__.py myapi mysite.sock uwsgi_myapi.log
uwsgi 大致完成,接下来我们来看 nginx~
nginx (发音为 engine-x) 是一个免费开源并且高性能的HTTP服务器和反向代理,还是一个IMAP/POP3代理服务器。
the web client <-> the web server
通过 yum install 命令可以直接安装:
(myvenv) [root@VM_0_11_centos myapi]# yum install nginx
中途会提示 "Is this ok [y/d/N]: " 直接输入 y 回车即可。
类似 myapi_uwsgi.ini,我们也是 vim 来建立编辑 myapi_nginx.conf 文件:
# myapi_nginx.conf
# the upstream component nginx needs to connect to
upstream djangomyapi {
server unix:///root/tedxapi/myapi/mysite.sock;
}
# configuration of the server
server {
# the port site will be served on
listen 8000;
# the domain name it will serve for
server_name 175.24.134.227;
charset utf-8;
access_log /root/tedxapi/myapi/logs/access.log;
error_log /root/tedxapi/myapi/logs/error.log;
# max upload size
client_max_body_size 75M;
location /static {
alias /root/tedxapi/myapi/static; # your Django project's static files - amend as required
}
location / {
uwsgi_pass djangomyapi; # 127.0.0.1:8002;
include /root/tedxapi/myapi/uwsgi_params;
}
}
注意 upstream djangomyapi 中 server unix: 后确实是三个斜杠,不能删减,后面指向的就是之前提到过的 mysite.sock 文件。完成编辑后保存退出该文件。
将这个文件链接到/etc/nginx/sites-enabled,这样nginx就可以看到它了,由于 我们环境中 /etc/nginx/下没有 sites-enabled 文件夹,我们先新建该文件夹,然后建立该配置文件的软连接过去:
(myvenv) [root@VM_0_11_centos static]# cd /etc/nginx/
(myvenv) [root@VM_0_11_centos nginx]# mkdir sites-enabled
(myvenv) [root@VM_0_11_centos nginx]# sudo ln -s /root/tedxapi/myapi/myapi_nginx.conf /etc/nginx/sites-enabled/
启动之前,我们先部署下静态文件:
(myvenv) [root@VM_0_11_centos myapi]# python manage.py collectstatic
可以通过 whereis nginx 查看 nginx 路径,当然如果你和我基本保持一致,使用 /usr/sbin/nginx 命令直接启动:
(myvenv) [root@VM_0_11_centos myapi]# /usr/sbin/nginx
由于我们之前启动过 uwsgi,可以先杀死所有 uwsgi 进程,然后再重新启动 uwsgi:
(myvenv) [root@VM_0_11_centos nginx]# pkill -f uwsgi -9
(myvenv) [root@VM_0_11_centos myapi]# uwsgi --ini myapi_uwsgi.ini
[uWSGI] getting INI configuration from myapi_uwsgi.ini
然后访问 http://175.24.134.227:8000/ 即可显示 API 数据:
点击其中的 http://175.24.134.227:8000/website/ 链接,结果如图:
至此,通过 nginx + uwsgi 运行 Django 项目成功实现。
此外,附上我搜集到的常用、可用的 uwsgi 和 nginx 命令:
查看 nginx 进程:
ps -ef | grep nginx
从容停止 kill -QUIT 主进程号
快速停止 kill -TERM 主进程号
强制停止 kill -9 nginx
查看 uwsgi 进程:
ps aux | grep uwsgi
杀死全部 uwsgi 进程命令:
pkill -f uwsgi -9
初始化 uwsgi 命令:
uwsgi --ini myapi_uwsgi.ini
加了 safe-pidfile 后,以后可以这样重启:
uwsgi --reload pid_myapi.pid
启动 nginx:
/usr/sbin/nginx
由于注册到备案完成周期较长,我新注册的域名暂时未进行域名解析和备案,而已完成备案的域名没有做整理记录,故此部分从简。
一般是在阿里云或腾讯云购买域名,例如我在阿里云买的 www.tedxpy.com 在腾讯云购置的 www.tedxmy.co
除了需要认证,域名解析会将域名与服务器 ip 绑定
此外,域名还需要备案,这个在腾讯云或阿里云都可以指引完成,时间也因地区而异。最终完成后即可通过域名取代服务器 ip 来实现域名访问了。
因为最终目的是拿该 API 接口给微信小程序开发使用,故要使用 https 来展现。
之前朋友推荐我用此链接中的方法去配置 https,但我最初尝试没能成功,估计和我最初把 Python2 软连接给改掉有关系,这个之后待验证。
我是通过阿里云免费证书完成了对 https 的配置。
首先在阿里云购买免费的云盾证书,然后按照此链接指引下载证书 .key 和 .pem 文件
与链接中不同的是,我将证书文件上传至了服务器的 /etc/nginx/cert/ 文件夹,因为 /etc/nginx 本身没有 cert 目录,故先在其中新建 cert 文件夹,然后本地直接通过 sftp 连接将 .key 和 .pem 上传至 /etc/nginx/cert/ 文件夹内。
同时由于已经拥有可用的域名 www.tedxpy.com 与服务器 ip 绑定,要将 myapi_nginx.conf 文件中的参数做修改:
# myapi_nginx.conf
# the upstream component nginx needs to connect to
upstream djangomyapi {
server unix:///root/tedxapi/myapi/mysite.sock;
}
# configuration of the server
server {
# the port site will be served on
#listen 8000;
listen 443 ssl;
# the domain name it will serve for
server_name www.tedxpy.com;
ssl_certificate /etc/nginx/cert/3188816_www.tedxpy.com.pem;
ssl_certificate_key /etc/nginx/cert/3188816_www.tedxpy.com.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
charset utf-8;
access_log /root/tedxapi/myapi/logs/access.log;
error_log /root/tedxapi/myapi/logs/error.log;
# max upload size
client_max_body_size 75M;
location /static {
alias /root/tedxapi/myapi/static;
}
location / {
uwsgi_pass djangomyapi; # 127.0.0.1:8002;
include /root/tedxapi/myapi/uwsgi_params;
}
}
由于升级 https,listen 8000 改为了 443 ssl;同时 server_name 也由 ip 改成了域名;同时配置了一系列 ssl 相关的参数,其中 ssl_certificate 对应的是新配置的证书.pem 文件,ssl_certificate_key 对应的是新配置的证书 .key 文件。
至于 myapi_uwsgi.ini 文件中:
# myapi_uwsgi.ini file
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /root/tedxapi/myapi
# Django s wsgi file
module = myapi.wsgi
# the virtualenv full path
home = /root/tedxapi/myvenv
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 2
# the socket (use the full path to be safe
socket = /root/tedxapi/myapi/mysite.sock
# ... with appropriate permissions - may be needed
chmod-socket = 666
# clear environment on exit
vacuum = true
daemonize = /root/tedxapi/myapi/uwsgi_myapi.log
safe-pidfile = /root/tedxapi/myapi/pid_myapi.pid
将之前配置的 http=:8000 去掉,无需使用端口了。
完成配置后重新运行 nginx 和 uwsgi,即可通过域名来访问 Django 项目了~
我所实现的成果是:
https://www.tedxpy.com/
https://www.tedxpy.com/weibo/
至此,整个 Django RESTFramework API 项目在服务器上部署展现的功能就实现了。
为了实现爬取的热榜数据按时更新,我还在服务器上通过 crontab 定时任务来执行爬虫取数据的代码,后续再整理文章更新~
以上,感谢阅读~
最后,也向你推荐我的微信公众号 TEDxPY,内容涉及 Python、小程序等,来找我哦~