毕设的一部分是做一个微信小程序。需要公网IP,因此需要购买云服务器,并且申请域名。正赶上华为云搞活动,结结实实的薅了一把羊毛。(华为云操作教程参考我的另一篇博客:。当然希望大家货比三家,看看哪个平台性价比高买哪个。)

后端小白经过摸索,终于完成了小程序的后台搭建,并做了一个小小的微信小程序demo。下面将详细记录整个搭建流程。

 

一、华为云端口放通

注意:若购买的腾讯云服务,是不需要这一步骤的。腾讯云是默认放通的,无需操作。但迁移到华为云之后,发现其他主机ping不通华为云(ICMP未通),并且无法访问域名(默认的80端口未开通)。因此需要手动放通端口才行。

1. 打开“控制台”——“弹性云服务器”,界面如下。点击服务名称进入。

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_ico

2. 更改安全组规则

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_Nginx_02

3. 选择“入方向规则”,将协议端口一键放通。

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_ico_03

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_nginx_04

二、后台搭建

参考链接:https://cloud.tencent.com/developer/article/1453563 (参考链接的有些步骤可以省略,具体请往下看)

1.准备域名、SSL证书、服务器

准备域名、SSL证书、服务器。在华为云的控制台添加解析记录。这一步骤不再详述。

 

2. 配置反向代理

(1)安装 Nginx

利用Nginx作为反向代理,搭建https服务。

在 Ubuntu 上,可直接使用 apt-get 来安装 Nginx

sudo apt-get install nginx -y

安装完成后,使用 nginx 命令启动 Nginx:

sudo /etc/init.d/nginx start

此时访问  华为云的公网IP 可以看到 Nginx 测试页面 

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_Nginx_05

(2)配置 HTTPS 反向代理

修改 /etc/nginx 目录的读写权限

sudo chmod a+rw /etc/nginx

将之前下载的 SSL 证书(解压后 Nginx 目录分别以 crt 和 key 作为后缀的文件)通过拖动到左侧文件浏览器 /etc/nginx 目录的方式来上传文件到服务器上。

如何上传 SSL 证书到 /etc/nginx 目录

在 /etc/nginx/conf.d 目录创建 ssl.conf 文件

cd /etc/nginx/conf.d
sudo touch ssl.conf
sudo chmod a+rw ssl.conf

将 ssl.conf 文件修改为如下内容

示例代码:/etc/nginx/conf.d/ssl.conf

server {
        listen 443;  #监听443端口,这个是ssl访问端口
        server_name www.sybil-chocolate.cn; # 改为绑定证书的域名
        # ssl 配置
        ssl on;
        ssl_certificate 1_www.sybil-chocolate.cn_bundle.crt; # 改为自己申请得到的 crt 文件的名称
        ssl_certificate_key 2_www.sybil-chocolate.cn.key; # 改为自己申请得到的 key 文件的名称
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers on;

        location / {
            proxy_pass http://127.0.0.1:5000; #默认端口为5000.可以根据flask后台做对应修改。
        }
    }

server{
     listen 80;  # 80端口是http正常访问的接口
     server_name www.sybil-chocolate.cn;
     rewrite ^(.*) https://$host$1 permanent; # https全加密处理,在访问http的时候自动跳转到https
    }

按 Ctrl + S 保存配置文件,让 Nginx 重新加载配置使其生效:

sudo nginx -s reload

此时,访问绑定的域名 www.example.com,应该可以看到如下结果,表示反向代理设置成功。但还没有启动后台程序,因此返回502。

微信小程序 后端管理系统实例 dockers 微信小程序后端部署_nginx_06

3. 基于Flask搭建后台服务

由于我们的程序是python语言编写,因此选用了flask框架作为我们的后端框架。以最简单的hello world 为例。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    # app.run('127.0.0.1', port=5000, debug=True)  
    app.run(debug=True)   //默认为 127.0.0.1:5000, 可以进行修改

若没有上述的反向代理配置过程,在浏览器中输入 127.0.0.1:5000, 即可在页面中显示 “hello world”了。但只能在当前主机访问。

配置了反向代理之后,浏览器中输入域名 https://www.example.com,可达到同样的显示效果,可供所有人访问

 

至此,最naive的后台搭建成功。

 

4. Gunicorn+gevent配置

作为一个轻量级的后端框架,Flask仅完成接收请求并返回执行结果的过程。但是用于生产环境无论是处理高并发还是鲁棒性都有所欠缺,一般会配合WGSI容器来进行生产环境的部署。gunicorn结合gevent,是一种比较常用的部署方式。

(1)安装gunicorn和gevent

pip install gunicorn
pip install gevent

 (2)启动gunicorn

简单地,gunicorn可以通过

gunicorn -w 4 -b 127.0.0.1:5000 test:app

启动一个Flask应用。其中,

  • -w 4是指预定义的工作进程数为4,
  • -b 127.0.0.1:5000指绑定地址和端口
  • test是flask所在的python文件,app则是flask应用程序实例

(3)gunicorn配置文件

gunicorn有非常多的配置项,因此通常会写成一个配置文件来进行配置。我所用项目的配置项如下:

# 并行工作进程数
workers = 3
# 指定每个工作者的线程数
threads = 1
# 监听内网端口5000
bind = '127.0.0.1:5000'
# 设置守护进程,将进程交给supervisor管理
daemon = 'true'
# 工作模式协程
worker_class = 'gevent'
# 设置最大并发量
worker_connections = 2000
# 设置进程文件目录
pidfile = '/var/run/gunicorn.pid'
# 设置访问日志和错误信息日志路径
accesslog = 'log/gunicorn_acess.log'
errorlog = 'log/gunicorn_info.log'
# 设置日志记录水平
loglevel = 'info'

这样,可以将gunicorn的日志输出至 log/gunicorn_info.log 中,便于查看。若只想打印报错信息,只需修改loglevel = 'error'即可。

(4)合并Flask和gunicorn的日志输出

参考链接:https://zhuanlan.zhihu.com/p/36909560

我的路由入口代码如下:

@app.route('/vectorization', methods=['POST'])
def vectorization():
 
    app.logger.info('Vectorization Start!')
    
    img = request.files.get('file')
    img_path = images_path + "cartoon/" + time.strftime('%Y%m%d_%H-%M-%S_', time.localtime(time.time())) + str(round(round(random.random(),4)*10000)) + ".png"
    img.save(img_path)

    seg_path=img_path.replace(".png","_s.png")
    sketch_path=img_path.replace(".png","_t.png")
    svg_path=img_path.replace(".png","_svg.svg")

    gen_svg(img_path,seg_path,sketch_path,svg_path)

   
    app.logger.info("img_path:"+img_path+'\n'+"svg_path:"+svg_path)
    app.logger.info('Vectorization Succeed!')

    return svg_path.replace(images_path,"")

该文件中添加如下语句:

if __name__ != '__main__':
    gunicorn_logger = logging.getLogger('gunicorn.error')
    app.logger.handlers = gunicorn_logger.handlers
    app.logger.setLevel(gunicorn_logger.level)

如此即可将Flask的日志也打印至 log/gunicorn_info.log中。如下:

[2019-12-09 19:16:13 +0800] [9225] [INFO] Starting gunicorn 19.4.5
[2019-12-09 19:16:13 +0800] [9225] [INFO] Listening at: http://127.0.0.1:5000 (9225)
[2019-12-09 19:16:13 +0800] [9225] [INFO] Using worker: gevent
[2019-12-09 19:16:13 +0800] [9228] [INFO] Booting worker with pid: 9228
[2019-12-09 19:18:01 +0800] [9228] [INFO] Parent changed, shutting down: <Worker 9228>
[2019-12-09 19:18:01 +0800] [9228] [INFO] Worker exiting (pid: 9228)
[2019-12-09 19:18:04 +0800] [10011] [INFO] Starting gunicorn 19.4.5
[2019-12-09 19:18:04 +0800] [10011] [INFO] Listening at: http://127.0.0.1:5000 (10011)
[2019-12-09 19:18:04 +0800] [10011] [INFO] Using worker: gevent
[2019-12-09 19:18:04 +0800] [10014] [INFO] Booting worker with pid: 10014
[2019-12-09 19:18:09 +0800] [10014] [INFO] Vectorization Start!
[2019-12-09 19:18:11 +0800] [10014] [INFO] img_path:/root/Vec_Server/static/cartoon/20191209_19-18-09_8533.png
svg_path:/root/Vec_Server/static/cartoon/20191209_19-18-09_8533_svg.svg
[2019-12-09 19:18:11 +0800] [10014] [INFO] Vectorization Succeed!
[2019-12-09 22:06:26 +0800] [10014] [INFO] Vectorization Start!
[2019-12-09 22:06:29 +0800] [10014] [INFO] img_path:/root/Vec_Server/static/cartoon/20191209_22-06-26_792.png
svg_path:/root/Vec_Server/static/cartoon/20191209_22-06-26_792_svg.svg
[2019-12-09 22:06:29 +0800] [10014] [INFO] Vectorization Succeed!

至此,完整的微信小程序后端搭建完毕。

 

三、小程序部署

笔者的小程序实现的功能为:拍照或从相册中选择图像,上传至服务器,进行图像风格化,并将风格化后的图像在小程序端展示,并提供保存功能。

目前小程序仍在制作中,完成后会release小程序端和客户端的关键代码。