有任何问题可以在评论区提问,我会的,尽量回答。

背景

公司的官网要更新,想做个产品返修进度查询。但是数据都在OA系统里面,所以需要写接口,把OA中的每个节点数据传给前端。
之前用nodejs实现过这个接口,但是由于这次官网做了SSL,所以它请求不了http的接口。因此,我不得不把接口做成https协议的。那与其做一遍SSL,不如把整个nodejs接口重构到python下(脑回路清奇,明明重构工作量大多了)。为啥选python,因为人生苦短。好吧,因为我现在是以开发运维的身份存在的,学点python对以后的自动化运维总有好处。

概述

项目本体由python3.6+flask+pymssql完成,使用uwsgi做容器发布,用nginx做https协议请求转发。

详细过程与配置

python代码(在python环境可以单独跑起来)

这一部分麻雀虽小五脏俱全,囊括了很多restful的知识(一天从python 0基础到写完接口,我骄傲)。

from collections import OrderedDict

import pymssql
import json
import datetime
from flask import Flask, request, jsonify
from sqlalchemy import null

app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
app.config['JSON_AS_ASCII'] = False

#用作解析数据库中的日期
class DateEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')

        elif isinstance(obj, datetime.date):
            return obj.strftime("%Y-%m-%d")

        else:
            return json.JSONEncoder.default(self, obj)


def queryRepair(sn):
    conn = pymssql.connect(host="10.0.0.11",
                           port=1433,
                           user="a",
                           password="a",
                           database="a",
                           charset='cp936')
    if conn:
        cursor = conn.cursor()
        sql = "select * from V_Kingorld_query_repair where sn = %s;"
        cursor.execute(sql, str(sn))
        col_names = [desc[0] for desc in cursor.description]
        result = []
        for row in cursor.fetchall():
            dict_obj = OrderedDict()
            for i, v in enumerate(row):  # index, value
                dict_obj[col_names[i]] = v
            result.append(dict_obj)

        # result = json.dumps(result, cls=DateEncoder, ensure_ascii=False)
        cursor.close()
        conn.close()
        if len(result):
            res = {
                "status": 0,
                "msg": "success",
                "data": result
            }
        else:
            res = {
                "status": 1,
                "msg": "sn无效",
                "data": result
            }
    else:
        res = {
            "status": 1,
            "msg": "fail",
            "data": null
        }
    return res



@app.route('/getNode', methods=['GET'])
def getNode():
    sn = request.args.get('sn')
    print(sn)
    txt = queryRepair(sn)
    return jsonify(txt)

if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port='3331')

python代码在此不赘述了。简单的restful接口而已。看不懂的地方可以提问。注意我中间注释的那一句result = json.dumps(result, cls=DateEncoder, ensure_ascii=False) 这句话,当时是用来解决数据库返回对象乱码问题的。后来发现,这么写是没必要转字符编码,否则会出现斜杠双引号的情况。原理就是,如果我先把数据库返回结果转成了json,那么在后面res={}这个json中,由于result是字符串,所以res会自动把result中的双引号用转义字符转一下。

我是用Pycharm写的代码,运行直接run就行。

传输到服务器

由于我的开发环境是 ubuntu18所以,直接一行命令搞定

scp /home/Kingorld/PythonProjects/repairQuery apiuser@10.0.0.10:/Api/Python/repairQuery

服务器环境搭建

服务器是CentOS8

# 首先安装python3.6 centos8自带3.6
yum install -y python
python --version #检查一下版本
pip --version #检查版本
# 创建python虚拟环境
cd /Api/Python/repairQuery
python -m venv venv
# 激活虚拟环境 用虚拟环境的好处就是,随便你怎么造,不影响其他环境
source ./venv/bin/activate
# 此时命令行前面会出现小括号  (venv)表示你现在是在虚拟环境中执行命令

# 安装我需要的包(根据项目不同,需要下载的包也不同)
(venv) pip install pymssql
(venv) pip install flask

# 安装uwsgi(不多介绍了)
(venv) pip install uwsgi

uwsgi配置

# 新建ini配置文件(可自定义命名)
(venv) touch uwsgi.ini
# 编辑
(venv) vim ./uwsgi.ini

以下是配置

[uwsgi]
# main文件所在目录
chdir=/APIs/python/repairQuery

# 文件里如果是 app.run  那就用app
callable=app

# flask文件名
wsgi-file=repairQuery.py

# 进程数
processes=1

# 使用3333端口
http=0.0.0.0:3333

# 日志输出目录
daemonize =/APIs/python/repairQuery/flask.log

# 关闭uwsgi时需要用到这个文件
pidfile = repairQuery.pid

然后保存退出即可

启动uwsgi

uwsgi --ini uwsgi.ini   # 启动后直接进控制台
nohup uwsgi --ini uwsgi.ini &    # 后台启动uwsgi服务器
uwsgi --reload uwsgi.pid  # 重启
uwsgi --stop uwsgi.pid # 停止
kill -9 pid   # 关闭服务,直接kill uwsgi的端口

nginx部分

首先下载安装nginx

# 如果还在虚拟环境需要先执行
# (venv) deactivate
# 安装nginx
yum install -y nginx
# 通过yum安装的nginx主目录一般在 /etc/nginx下
# 因为这是个接口服务器,所以我的nginx可能会代理多个端口。因此,我把每个系统的接口都新建了不同的配置文件
# 因为nginx自动会识别到conf.d目录下的所有配置,所以直接新建就好了
# 具体的代码在nginx.conf中是  include /etc/nginx/conf.d/*.conf
# 把默认的文件复制到/etc/nginx/conf.d下并且重命名为repairQuery.conf(需要sudo权限)
sudo cp /etc/nginx/nginx.conf /etc/nginx/conf.d/OA/repairQuery.conf
# 接着把pem文件和key文件(证书)上传到服务器
# 在nginx文件夹下新建cert目录(需要sudo权限)
sudo mkdir /etc/nginx/cert
# 把上传的文件移动到cert目录下
sudo mv /home/kingorld/aaa.pem  /etc/nginx/cert
sudo mv /home/kingorld/aaa.key  /etc/nginx/cert

修改配置文件为以下内容

#二级域名
server {
        listen 443 ssl ;
        server_name aaa.com ; # 这是申请证书时候的域名
        # 把你的pem文件和key文件的目录下载下面
        ssl_certificate      cert/aaa.pem;
        ssl_certificate_key  cert/aaa.key;
        ssl_session_timeout  5m;

        ssl_protocols  SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2 ;
        ssl_ciphers  ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers   on;

        location / {
        		#下面的3333端口就是uwgsi的http端口
                proxy_pass http://127.0.0.1:3333;
                add_header Access-Control-Allow-Origin *;
                # 当然由于这里只是转发请求,所以没有跳转index
                # 如果需要跳转index页面的话需要加上root和index路径
        }
}

下面启动nginx

# 先检查nginx状态
systemctl status nginx
# 如果开启了,重新加载一下配置就行(一般需要sudo权限)
sudo nginx -s reload
# 如果没有开启,需要启动nginx(一般需要sudo权限)
sudo systemctl start nginx
sudo systemctl restart nginx # 这条是重启命令
sudo systemctl stop nginx # 停止nginx

此时应该可以请求到接口数据了。
如果不行可以去看下uwgsi日志和nginx日志。一定要记得看日志,别瞎TM整。

容易忽略的地方

1. 服务是否开启

如果请求出现了502,可能是服务没有开启。由于现在已经用nginx代理了,所以外网(包括postman)的请求都是502.
第一步,可以先在服务器上面用curl命令测试一下是否能够获取到数据。

curl localhost:3333/getNode?sn=1

如果获取到数据,说明服务开启,并且能正常访问。如果返回是什么empty server之类的或者压根没有返回(长时间无返回),就是异常启动。
此时就要去查看uwsgi日志,看服务是否正常启动。

2. 防火墙端口是否开启

检查443端口和3333端口是否开启(一般3333服务器内部访问,只开启443端口就行)

# 先看防火墙状态是否正常 我用的是firewalld  你可能用其他的
systemctl status firewalld
# 如果防火墙没开启,这个问题跳过,跟防火墙没关系。如果开启,继续看端口是否开启。
firewall-cmd --zone=public --query-port=443/tcp
# 如果显示yes,那也不是端口问题。如果显示no,继续开启443端口
firewall-cmd --zone=public --add-port=443/tcp

此时如果还是请求不到。首先去看日志

3. selinux问题

关于selinux不深究,究了你也不明白。当然我目前也不是很清楚。如果你明白的话,可以跟我探讨交流。
所以对于selinux,关掉吧。

# 查看selinux状态,如果是1,置为0
getenforce
# 关闭selinux(临时关闭,重启服务器又会开启。永久关闭selinux方法自行百度)
setenforce 0

如果还是不行。还是看日志,百度 (为啥推荐百度,因为83.64%的程序员上不了google,能上的也有92.37%的人不想看英文)。

4.permission denied问题

权限不足问题。可能由nginx权限不足和selinux导致。selinux问题参照3。
如果是nginx问题。
设置nginx的权限为root(最高权限)

# 编辑/etc/nginx/nginx.conf
vim /etc/nginx/nginx.conf
# 修改nginx权限为root
# 找到user nginx(或者其他权限) 修改为如下
user root

结语

CentOS+flask+uwsgi+nginx+ssl的部署就到这里。如果你是python开发工程师,那么比较难的部分应该是nginx和ssl。如果你是运维工程师,那么应该是python代码问题比较多。
好了,以上就是我在开发与部署过程中碰到的一些问题,如果各位看官有不同意见或者看法的,随时在评论区回复,我看到会响应的。
最后,挚谢阅读