说实话此次的项目对个人提高并不大,不管是前端、后端我过去都有所经验,对于团队协做、版本控制、自动化CI/CD也有所了解。因此本篇博客我不会将主要的分析放在先后端的实现上,更多的着眼于部署等方面。javascript
附项目体验地址。php
咱们完成的是典型的先后端分离项目,首先要作的就是落实先后端交互格式,咱们采用了JSON
这种轻量的数据交换格式,具体格式约定以下:前端
{ "status": "success", "data": interface{} }
{ "status": "error", "err_msg": "error message" }
接下来咱们要作的就是先后端的分别实现,前端的实现咱们放到代码复用部分讲,这里咱们看看后端。后端咱们选择Python
做为主要的开发工具,咱们先来看APP的实例获取过程:java
from flask import Flask from flask_cors import CORS from app.config import FlaskConfig from app.controllers import register_routers from app.models import connect_db def new_flask_app() -> Flask: app = Flask(__name__) CORS(app, supports_credentials=True) # 添加配置文件 app.config.from_object(FlaskConfig) # 注册路由 register_routers(app) # 连接数据库 connect_db(app) return app
代码中的注释都比较详细,不想讲不少。你们注意一下Python中的类型注解这一个特性这样能够得到很是好的代码提示等IDE支持。python
接下来,咱们分别看一个Model和Controller的例子:react
from app.models import db from app.models import session_commit class User(db.Model): id = db.Column(db.Integer, autoincrement=True, primary_key=True) username = db.Column(db.String, nullable=True) password = db.Column(db.String, nullable=True) def __init__(self, username, password): self.username = username self.password = password def __str__(self): return "User(username={})".format(self.username) @classmethod def check_password(cls, username: str): return cls.query.filter_by(username=username).first() @classmethod def change_password(cls, username: str, password: str): user = cls.query.filter_by(username=username).first() user.password = password return session_commit() def new_user(self): db.session.add(self) return session_commit()
注意其中类方法的使用便可,其他的就是简单的Python的ORM的使用nginx
from flask import Blueprint, request, session from app.models.user import User import app.utils.return_warp as warp login_out_page = Blueprint('login_out', __name__, url_prefix='/log') @login_out_page.route('/in', methods=['POST']) def login(): username = request.form.get('username') password = request.form.get('password') # 校验必须参数 if username is None or password is None: return warp.fail_warp('params error') user = User.check_password(username=username) if user.password == password: session.clear() session['user'] = username return warp.success_warp('login success') else: return warp.fail_warp('user error') @login_out_page.route('/out', methods=['GET']) def logout(): session.clear() return warp.success_warp('logout success')
其他的内容便再也不赘述,具体的代码实现也没有什么难懂的地方,也没什么讲解的必要。docker
本次项目咱们主要复用的是前端部分的代码,并在其基础上进行了优化。数据库
能够说本次结对编程,个人队友负责前端部分,由于复用的是我我的项目时的前端代码,因此咱们采用的是React
这样的技术。个人队友对于如今前端工程化的方法有了很大的理解,对于前端工做流的使用也初步进行了入门,对于流行的MVVM模型有了深刻的理解。编程
接下来举一个React的Context的例子说明是怎么进行代码复用的:
// 我的项目代码 import React, {createContext, useState} from 'react'; export const TypeContext = createContext(null); export const TypeProvider = props => { let [userType, setUserType] = useState({ name: '张三1', type: 1 }); return ( <TypeContext.Provider value={{userType, setUserType}}> {props.children} </TypeContext.Provider> ) }; export const TypeConsumer = TypeContext.Consumer; //结对项目 import React, {createContext, useState} from 'react'; export const UserContext = createContext(null); export const TypeProvider = props => { const [user, setUser] = useState(''); const [errorMessage, setErrorMessage] = useState(''); return ( <UserContext.Provider value={{user, setUser, errorMessage, setErrorMessage}}> {props.children} </UserContext.Provider> ) }; export const TypeConsumer = UserContext.Consumer;
能够看到二者的代码基本上是一致的,只是咱们所须要共享的数据不太同样,因此对外提供了不一样的Provide。
有兴趣的能够了解一下React Hooks的原理和使用
Docker是一个开放源代码软件项目,让应用程序部署在软件货柜下的工做能够自动化进行,借此在Linux操做系统上,提供一个额外的软件抽象层,以及操做系统层虚拟化的自动管理机制。 Docker利用Linux核心中的资源分离机制,例如cgroups,以及Linux核心名字空间,来建立独立的容器。
咱们的后端项目即采用Docker进行部署,具体的命令等你们能够查看Docker官网,下面给出Dockerfile:
# 基础镜像 FROM python:3.7 WORKDIR /app ADD . /app RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple CMD ["gunicorn", "main:app", "-c", "gunicorn.conf.py"]
Nginx是异步框架的网页服务器,也能够用做反向代理、负载平衡器和HTTP缓存。该软件由伊戈尔·赛索耶夫建立并于2004年首次公开发布。 2011年成立同名公司以提供支持。2019年3月11日,Nginx公司被F5 Networks以6.7亿美圆收购。 Nginx是免费的开源软件,根据类BSD许可证的条款发布。
咱们的服务器只在44三、80两个端口运行,其他的部署经过Nginx反代进行:
#PROXY-START/pair location /pair { expires 12h; if ($request_uri ~* "(php|jsp|cgi|asp|aspx)") { expires 0; } proxy_pass http://内网IP:6000/; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header REMOTE-HOST $remote_addr; add_header X-Cache $upstream_cache_status; add_header Cache-Control no-store; proxy_cache cache_one; proxy_cache_key $host$uri$is_args$args; proxy_cache_valid 200 304 301 302 1m; } #PROXY-END/pair
注意其中由于使用了Docker不能够使用localhost,必须使用内网IP,记得做为API服务器应该设置不开启浏览器缓存。