【学习笔记】理解HTTP协议&Python实现一个简单的web框架

网址和HTTP协议组成

网址组成(四部分)

1,协议 http, https(https 是加密的 http)

2,主机 g.cn zhihu.com之类的网址

3,端口 HTTP 协议默认是 80,因此一般不用填写

4,路径 下面的「/」和「/question/31838184」都是路径

http://www.zhihu.com/

http://www.zhihu.com/question/318381

HTTP协议组成:

1,请求行或者响应行

2,Header(请求的 Header 中Host 字段是必须的,其他都是可选)

3,\r\n\r\n(连续两个换行回车符,用来分隔Header和Body)

4,Body(可选)

一些Header字段:

1,connection:keep-alive

2,........

实现一个简单的web框架

实现流程:解析request,执行相应的路由函数,给HTML模板填充数据,拼装response,返回给浏览器

设置cookie:通过给response的header里添加字段Set-Cookie

实现session:session的结构是:

List<Map<Map>>
session={
    'session id' {
        'username':'zhangsan'
        'password':'123'
    },
    session id' {
        'username':'zhangsan'
        'password':'123'
    }
}

session 持久化(持久化就是重启后仍然可以使用)的两种方案:保存到文件;对称加密(将user信息加密保存到cookie,这样可以不用存储session)

实现重定向:给response的header里添加字段Location:url,把状态码设置为301或302

部分代码:

server.py:监听请求,调用相应的路由函数,返回响应

import socket
from utils import log
from modules.Request import Request
from utils import parsed_request
from utils import response_for_path


def run(host, port):
    log('server start at:{}:{}'.format(host, port))
    with socket.socket() as s:
        s.bind((host, port))
        s.listen(5)
        while True:
            conn, addr = s.accept()
            r = conn.recv(1000).decode('utf-8')
            # 过滤掉空请求
            if len(r.split()) < 2:
                conn.close()
            method, path, query, headers, cookies, body = parsed_request(r)
            request = Request()
            request.method = method
            request.path = path
            request.query = query
            request.headers = headers
            request.cookies = cookies
            request.body = body

            response = response_for_path(request)
            conn.send(response)


if __name__ == '__main__':
    run('localhost', 3000)

 

utils.py:解析request,根据请求路径调用相应的路由函数

import time
from routes.route_index import route_index
from routes.route_static import route_static
from routes.route_register import route_register
from routes.route_login import route_login


# 循环引入会报错

def log(*args, **kwargs):
    for_mat = '%H:%M:%S'
    value = time.localtime(int(time.time()))
    dt = time.strftime(for_mat, value)
    # with open('log.txt', 'a', encoding='utf-8') as f:
    #     print(dt, *args, file=f, **kwargs)
    print(dt, *args, **kwargs)


def error(code=404):
    e = {
        404: b'HTTP/1.1 404 NOT FOUND\r\n\r\n<h1>NOT FOUND</h1>',
    }
    return e.get(code, b'')


def parsed_request(request):
    """
    解析请求(str),返回method,path,query,headers,cookies,body
    GET /xxx/xx?a=1&b=1 HTTP/1.1
    """
    # 解析method
    method = request.split()[0]
    # 解析path,query
    if method == 'GET':
        path_query = request.split()[1]
        i = path_query.find('?')
        if i > 0:
            path = path_query[:i]
            query_string = path_query[i + 1:]
            query = {}
            query_list = query_string.split('&')
            for o in query_list:
                k, v = o.split('=')
                query[k] = v
        else:
            path = path_query
            query = {}
    else:
        path = request.split()[1]
        query_string = request.split('\r\n\r\n')[1]
        query = {}
        query_list = query_string.split('&')
        for o in query_list:
            k, v = o.split('=')
            query[k] = v
    # 解析headers,cookies
    headers = {}
    cookies = {}
    request_header = request.split('\r\n\r\n')[0]
    header_str = request_header.split('\r\n')
    header_str.pop(0)
    for o in header_str:
        # 注意Host: localhost:4000,Host冒号后面有空格
        k, v = o.split(': ')
        if k == 'Cookie':
            for x in v.split(';'):
                k, v = x.split('=')
                cookies[k] = v
        else:
            headers[k] = v
    # 解析body
    if method == 'GET':
        body = ''
    else:
        body = request.split("\r\n\r\n")[1]
    return method, path, query, headers, cookies, body


def response_for_path(request):
    """
    根据路径调用相应的路由函数,获得response
    """
    path = request.path
    r = {
        '/': route_index,
        '/static': route_static,
        '/register': route_register,
        '/login': route_login,
    }
    response = r.get(path, error)
    return response(request)

route_index.py:主页的路由函数

from . import templates
from . import current_user


def route_index(request):
    """
    主页的路由函数
    """
    session = current_user(request)
    name = ''
    if session is not None:
        session_id = request.cookies.get(' session-id')
        name = session[session_id]['username']

    header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
    body = templates('index.html')
    body = body.replace('{{ }}', '欢迎你:{}'.format(name))
    r = header + '\r\n' + body
    return r.encode('utf-8')

完整的代码可访问我的gitee仓库:https://gitee.com/TearsGit/server

 

 

 

转载于:https://my.oschina.net/u/3943244/blog/3096362

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值