Skip to content

第一次数据请求,服务器接收用户注册信息

本小节将是我们编写服务器端代码的开始。现在假设有这样一个 App(见下图),用户需要通过该界面提交注册信息。服务器端在接收到客户端的注册请求后,返回注册成功信息,并将该用户写入数据库表用户信息中。

客户端模拟

考虑到本小册讲解的是服务器端,这里不作 App 端的介绍,我们将使用 HTTP 发包工具来模拟上面的 App 注册信息的提交。

HTTP 发包工具:Getman

约定服务器端 HTTP server 的端口号为 8000,服务器端和客户端定义的请求是 /users/regist,那么完整的 URL 为 http://150.109.33.132:8000/users/regist?(请用自己的云虚拟机 IP 替换其中的 IP)。 参数为手机号(phone)、密码(password)及验证码(code),参数放入 HTTP 的 body 中,具体为: {"phone":"18866668888","password":"demo123456","code":"123456"}

注:

  1. 确保服务器端 8000 端口已放通;
  2. 在实际的项目中,密码不会明文的传输,一般会在客户端先使用 md5 进行加密,服务器端存储的也是加密后的密码字符串。本小册作为学习示例,将使用明文讲解。

发包器模拟如下:

客户端的请求至此已初步完成,现在,服务器端接收到客户端这个请求后,将如何处理呢?

服务器端处理

调用逻辑

客户端以 POST 的方式,发送注册请求至服务器端,请求进入服务器端的 main.py 后,将调用 url_router 转发到 users_url.py 中,在 users_urls.py 中,对应的 URL 将调用 users_views.pyRegistHandle 类, RegistHandle 为真正的代码处理逻辑,在校验用户信息正确的情况下,返回 JSON 格式的注册成功信息给客户端。

编写服务器端入口函数

main.py 是 Tornado 作为 HTTP 服务器的统一入口,根据前面的约定,Tornado 对外服务的端口号为 8000。

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-
# Author: demo
# Email: demo@demo.com
# Version: demo

import tornado.ioloop
import tornado.web
import os
import sys
from tornado.options import define,options

class Application(tornado.web.Application):
    def __init__(self):
        #定义 Tornado 服务器的配置项,如 static/templates 目录位置、debug 级别等
        settings = dict(
            debug=True,
            static_path=os.path.join(os.path.dirname(__file__),"static"),
            template_path=os.path.join(os.path.dirname(__file__), "templates")
        )
        tornado.web.Application.__init__(self, **settings)
 
 
 
if __name__ == '__main__':
    print ("Tornado server is ready for service\r")
    tornado.options.parse_command_line()
    Application().listen(8000, xheaders=True)
    tornado.ioloop.IOLoop.instance().start()

保存 main.py 代码后,在服务器端运行此段代码

此时再次点击 HTTP 发包模拟器发送注册信息
URL: http://150.109.33.132:8000/users/regist?
入参:{"phone":"18866668888","password":"demo123456","code":"123456"}

再次查看服务器端

此条打印说明,客户端的 HTTP 请求已到达服务器,服务器接收成功但处理失败了,原因为找不到路径 /users/regist。下面在服务器端编写针对 /users/regist 的处理代码。

编写路由转发

首先,服务器端从 main.py 收到客户端的请求后,需要将其转发给对应的处理模块。进入 common 目录,创建 url_router.py 文件

url_router.py 中输入如下代码。

python
#!/usr/bin/python3
# -*- coding:utf-8 -*-

from __future__ import unicode_literals
from importlib import import_module

def include(module):
    '''根据传入的字符串,调用相应的模块,如 module 为字符串 regist 时,
    调用views.users.users_views.RegistHandle 模块
    '''
    res = import_module(module)
    urls = getattr(res, 'urls', res)
    return urls
    
    
def url_wrapper(urls):
    '''拼接请求 url,调用对应的模块,如拼接 users 和 regist 成 url /users/regist,
    调用 views.users.users_views.RegistHandle 模块
    '''
    wrapper_list = []
    for url in urls:
        path, handles = url
        if isinstance(handles, (tuple, list)):
            for handle in handles:
                #分离获取字符串(如regist)和调用类(如views.users.users_views.RegistHandle)
                pattern, handle_class = handle
                #拼接url,新的url调用模块
                wrap = ('{0}{1}'.format(path, pattern), handle_class)
                wrapper_list.append(wrap)
        else:
            wrapper_list.append((path, handles))
    return wrapper_list

接下来修改 main.py,调用 url_router.py 将用户请求的路径转发给对应的请求模块。

增加如下几行,从 common 目录的 url_router 导入所需函数( from common.url_router import include, url_wrapper),并在 Application 的类中,拼接转发路由。

完成后的代码如下:

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-
# Author: demo
# Email: demo@demo.com
# Version: demo

import tornado.ioloop
import tornado.web
import os
import sys
from tornado.options import define,options
from common.url_router import include, url_wrapper
from tornado.options import define,options


class Application(tornado.web.Application):
    def __init__(self):
        handlers = url_wrapper([
        (r"/users/", include('views.users.users_urls'))
        ])
        #定义 Tornado 服务器的配置项,如 static/templates 目录位置,debug 级别等
        settings = dict(
            debug=True,
            static_path=os.path.join(os.path.dirname(__file__),"static"),
            template_path=os.path.join(os.path.dirname(__file__), "templates")
        )
        tornado.web.Application.__init__(self, handlers, **settings)
 

if __name__ == '__main__':
    print ("Tornado server is ready for service\r")
    tornado.options.parse_command_line()
    Application().listen(8000, xheaders=True)
    tornado.ioloop.IOLoop.instance().start()

至此,main.py 的路由转发已完成,接下来将编写真正的处理模块。

进入 views 目录,创建 users 目录,该目录将存放所有跟用户信息处理相关的代码。在该目录下,创建 users_urls.pyusers_views.py

其中,users_urls.py 处理针对 users 相关的路由及调用类之间的路由,users_views.py 为真正的逻辑处理。在 users_urls.py 中输入如下代码:

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-


from __future__ import unicode_literals
from .users_views import (
    RegistHandle
)

urls = [
    #从 /users/regist 过来的请求,将调用 users_views 里面的 RegistHandle 类
    (r'regist', RegistHandle)
]

users_views.py 文件中,输入如下代码:

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-

import tornado.web
from tornado.escape import json_decode

# 从commons中导入http_response方法
from common.commons import (
    http_response,
)

# 从配置文件中导入错误码
from conf.base import (
    ERROR_CODE,
)
 
class RegistHandle(tornado.web.RequestHandler):
    """handle /user/regist request
    :param phone: users sign up phone
    :param password: users sign up password
    :param code: users sign up code, must six digital code
    """
        
    def post(self):
        try:
            #获取入参
            args = json_decode(self.request.body)
            phone = args['phone']
            password = args['password']
            verify_code = args['code']
        except:
            # 获取入参失败时,抛出错误码及错误信息
            http_response(self, ERROR_CODE['1001'], 1001)
            return 
            
        # 处理成功后,返回成功码“0”及成功信息“ok”
        http_response(self, ERROR_CODE['0'], 0)

users_views.py 中看到,我们从公共方法库(commons)中导入了方法,并从配置文件中导入了错误码定义。接下来编写 commonsbase 配置文件。 进入 common 目录,并创建 commons.py 文件,在 commons.py 中输入如下代码:

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-

import json

def http_response(self, msg, code):
    self.write(json.dumps({"data": {"msg": msg, "code": code}}))

        
if __name__ == "__main__":
   http_response()

在 conf 目录下,创建 base.py 文件:

base.py 文件中,输入如下代码:

python
#! /usr/bin/python3
# -*- coding:utf-8 -*-

ERROR_CODE = {
    "0": "ok",
    #Users error code
    "1001": "入参非法"
}

至此,我们已经完成了基本的用户注册以及服务器端处理逻辑代码,重新运行 main.py,查看是否启动正常。

现在再从 HTTP 发包模拟器

此时看到返回的 JSON 消息已成功。

再次查看服务器端,此时控制台打印的 log 提示 HTTP 200,表示该条 URL 请求已正确处理并返回。

假如此时 HTTP 发包模拟器入参少了 code 参数,将提示错误信息。

至此,我们第一次客户端与服务器端的数据请求及回复已讲解完毕。完成后的目录结构及文件如下。

代码下载

到目前为止,服务器端代码如下:
demo6

小结

本小节讲解了客户端与服务器端的第一次数据请求及回复。代码比较简单,重点在于理解其中的 URL 路由转发,以达到触类旁通的效果。代码还有很多待完善的地方,如增加 log 管理,进一步抽象类和方法等。下一小节,我们将为代码加入 log 管理。

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我