美文网首页
手动实现一个简单的web框架

手动实现一个简单的web框架

作者: aq_wzj | 来源:发表于2019-11-28 16:20 被阅读0次

功能

  • 可处理get,post等请求
  • 视图函数,路由等文件分层
  • 返回html文件, 模板语言的使用

目录结构:

root@Jobs-lenovo:/mnt/c/Users/jobs/Desktop/study# tree web_frames/
web_frames/
├── templates ==========html文件夹
│   ├── index.html======首页
│   └── login.html======登录页面
├── url.py==============路由
├── views.py============视图函数
└── web_frame.py========socket服务
1574928171905.png

各个文件代码:

1. web_frame.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# @Author  : Wang Zhaojin
# @Time    : 2019/11/27 17:27
# @File: web_frame.py
# @Software: PyCharm
import socket
from web_frames import url


def get_request(recv_data):
    """
    构建请求信息
    :param recv_data: 浏览器发的请求,二进制数据
    :return: request={
                    "path":"/login",
                    "method":"GET",
                    "data":{"name":"admin","pwd":"password"}
                    }
    """
    # 获取url路径
    try:
        path = recv_data.decode('utf-8').split(' ')[1]
    except Exception as e:
        path = '/'
        print('path Error', e)
    # 获取请求方法
    try:
        method = recv_data.decode('utf-8').split(' ')[0]
    except Exception as e:
        method = 'GET'
        print('method Error', e)

    # 获取请求体数据
    try:
        all_data = recv_data.decode('utf-8').split('\r\n\r\n')
        data = {}
        if all_data[-1]:
            lis_data = all_data[1].split('&')
            for one_data in lis_data:
                key, value = one_data.split('=')
                data[key] = value
    except Exception as e:
        data = {}
        print('data Error', e)

    request = {
        'path': path,
        'method': method,
        'data': data
    }
    return request


def make_server(ip, port):
    """
    :param ip: 访问ip
    :param port: 访问端口
    :return:
    """
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(10)
    print('Starting development server at http://%s:%s' % (ip, port))
    while True:
        conn, addr = sock.accept()
        recv_data = conn.recv(1024)
        requests = get_request(recv_data)
        # 路由分发,根据路由进入对应的视图函数
        for i in url.urls:
            if requests['path'] == i:
                res = url.urls[i](requests)
                break
        else:
            res = {
                'status_code': '404',
                'status_msg': 'Not Found',
                'content': 'page is not found',
            }
        conn.send(('HTTP/1.1 %s %s\r\n' % (res['status_code'], res['status_msg'])).encode("utf-8"))
        # 3.2 返回响应头(可以省略)
        conn.send(b'Content-Type: text/html\r\n\r\n')

        conn.send(res['content'].encode("utf-8"))
        conn.close()


if __name__ == '__main__':
    make_server('127.0.0.1', 8008)

url.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# @Author  : Wang Zhaojin
# @Time    : 2019/11/27 17:57
# @File: url.py
# @Software: PyCharm
from web_frames import views

urls = {
    '/': views.index,
    '/login': views.login,
}

views.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# @Author  : Wang Zhaojin
# @Time    : 2019/11/27 17:57
# @File: views.py
# @Software: PyCharm


def response(content, status_code=200, status_msg='OK'):
    """
    构建返回需要的数据
    :param content: 返回数据
    :param status_code: 状态码
    :param status_msg: 状态描述
    :return: 
    """
    status_info = {
        '1': 'OK',
        '2': 'OK',
        '3': 'Redirect',
        '4': 'Not Found',
        '5': 'Server Error'
    }
    for i in status_info:
        if str(status_code).startswith(i):
            status_msg = status_info[i]
    
    res = {
        'status_code': str(status_code),
        'status_msg': status_msg,
        'content': content,
    }
    return res


def render_template(html_name, data={}):
    """
    返回html文档
    :param html_name: 返回的html文件名称
    :param data: 模板数据
    :return: response()
    """
    content = ''
    html_name = './templates/' + html_name
    with open(html_name, 'rt', encoding='utf-8')as f:
        content += f.read()
    if data:
        # 有模板变量
        for i in data:
            if '{{ ' + i + ' }}' in content:
                content = content.replace('{{ ' + i + ' }}', data[i])
    return response(content)


##############################################################################
#                                  视图函数                                   #
##############################################################################
def index(requests):
    """
    主页
    :param requests: 
    :return: 
    """
    return render_template("index.html", data={'arg1': 'hello'})


def login(requests):
    """
    登录页
    :param requests: 
    :return: 
    """
    if requests['method'] == 'GET':
        return render_template("login.html")

    elif requests['method'] == 'POST':
        name = requests['data']['name']
        pwd = requests['data']['pwd']
        if name == 'admin' and pwd == 'password':
            return response('login success')
        else:
            return response('name or password Error', status_code=500)
    else:
        return response('error', status_code=500)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<h1>This is Index Page</h1>
{{ arg1 }}
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="/login" method="post">
    <label for="name">用户名</label><input type="text" id="name" name="name">
    <label for="pwd">密码</label><input type="password" id="pwd" name="pwd">
    <input type="submit" value="提交">
</form>
</body>
</html>

相关文章

网友评论

      本文标题:手动实现一个简单的web框架

      本文链接:https://www.haomeiwen.com/subject/cdvbwctx.html