网址和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