浏览器请求动态页面过程
一个浏览器请求一个资源的时候 web服务器一定会根据相应的判断条件 如果判断是动态的 就调用框架里面的application函数 当这个函数调用完的时候 需要返回一个body
多进程 面向对象 web服务器:
import socket
import multiprocessing
import re
class WSGIServer(object):
def __init__(self):#创建对象的时候 套接字就创好
# 1 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置套接字 让套接字可以重复利用这个资源
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2 绑定
self.tcp_server_socket.bind(('', 7878))
# 3 默认套接字主动改为被动
self.tcp_server_socket.listen(128)
def send_data(self,new_socket): # 为这个客户端返回数据
# 1 接受浏览器发送过来的请求 即http请求
# GET / HTTP/1.1
# .....
request = new_socket.recv(1024).decode('utf-8')
print(request)
request_line = request.splitlines()
print(request_line) # 返回的是一个列表
ret = re.match(r'[^/]+(/[^ ]*)', request_line[0]) # GET /index.html HTTP.1.1
if ret:
file_name = ret.group(1) # 提取客户端想要的html文件名
if file_name == '/':
file_name = '/index.html' # 如果没有输入页面 就默认index.html当作页面
# 2 返回http格式的数据 给浏览器
try:
# 打开想要的文件
f = open(file_name, 'rb') # 二进制的形式直接读取 后面就不用编码了
except: # 找不到文件就返回NOT FOUND
response = 'HTTP/1.1 404 NOT FOUND\r\n'
response += '\r\n'
response += '-----not found---'
new_socket.send(response.encode('utf-8'))
else: # 如果能打开文件就读取并发送
html_contend = f.read()
f.close()
# 2.1 准备发送给浏览器的数据---header
response = "HTTP/1.1 200 OK\r\n"
response += '\r\n' # 空行加body
# response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
new_socket.send(response.encode('utf-8'))
new_socket.send(html_contend) # 不能和response一起发过去 因为是二进制的
new_socket.close()
def run_forever(self):
while True:
# 4 等待客户端连接
new_socket, client_add = self.tcp_server_socket.accept()
# 多进程
# 不用多进程的时候 需要等待服务完之后才能服务下一个
# 可以在接受连接的时候开一个进程 让进程里面的线程服务
# accept还是一个 分配任务的时候多个人去做
p = multiprocessing.Process(target=self.send_data, args=(new_socket,)) # 5 为这个客户端服务
p.start()
new_socket.close() # 需要再次关闭 因为子进程会复制父进程的资源 在创建进程之前的父进程的所有变量都会被复制一份
# 所以子进程中也有new_socket 但是都标记的一个客户端
##5 为这个客户端服务
# send_data(new_socket)
# 6 关闭监听套接字
tcp_server_socket.close()
def main():
wsgi_server = WSGIServer()
wsgi_server.run_forever()
if __name__ == "__main__":
main()
实际中的数据请求:
修改之前的代码的2 返回http格式数据这段代码:
# 2 返回http格式的数据 给浏览器
#2.1 如果请求的资源不是以.py结尾 那么就认为是静态资源(html/css/js/png jpg等)
if not file_name.endswith(".py"):
try:
# 打开想要的文件
f = open(file_name, 'rb') # 二进制的形式直接读取 后面就不用编码了
except: # 找不到文件就返回NOT FOUND
response = 'HTTP/1.1 404 NOT FOUND\r\n'
response += '\r\n'
response += '-----not found---'
new_socket.send(response.encode('utf-8'))
else: # 如果能打开文件就读取并发送
html_contend = f.read()
f.close()
# 2.1 准备发送给浏览器的数据---header
response = "HTTP/1.1 200 OK\r\n"
response += '\r\n' # 空行加body
# response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
new_socket.send(response.encode('utf-8'))
new_socket.send(html_contend) # 不能和response一起发过去 因为是二进制的
else:#一下代码最好再写一个py文件 (解耦)
#2.2 如果以.py结尾 呢么就认为是动态资源的请求
header = "HTTP/1.1 200 OK\r\n"
header += '\r\n'
body = "hahahhahahhaha %s" % time.ctime()
response = header+body
#发送response给浏览器
new_socket.send(response.encode('utf-8'))
new_socket.close()
1---------------------------------
简单的解耦(将web服务器和逻辑代码分开):
# 2 返回http格式的数据 给浏览器
# 2.1 如果请求的资源不是以.py结尾 那么就认为是静态资源(html/css/js/png jpg等)
if not file_name.endswith(".py"):
try:
# 打开想要的文件
f = open(file_name, 'rb') # 二进制的形式直接读取 后面就不用编码了
except: # 找不到文件就返回NOT FOUND
response = 'HTTP/1.1 404 NOT FOUND\r\n'
response += '\r\n'
response += '-----not found---'
new_socket.send(response.encode('utf-8'))
else: # 如果能打开文件就读取并发送
html_contend = f.read()
f.close()
# 2.1 准备发送给浏览器的数据---header
response = "HTTP/1.1 200 OK\r\n"
response += '\r\n' # 空行加body
# response += '<b1>hehehe</b1>'#2.2 发送给浏览器的数据body
new_socket.send(response.encode('utf-8'))
new_socket.send(html_contend) # 不能和response一起发过去 因为是二进制的
else:
#2.2 如果以.py结尾 呢么就认为是动态资源的请求
header = "HTTP/1.1 200 OK\r\n"
header += '\r\n'
body = mini_frame.application(file_name)
response = header+body
#发送response给浏览器
new_socket.send(response.encode('utf-8'))
逻辑代码 mini_frame.py:
#逻辑处理代码
import time
def login():
return "---login--welcome to our web time %s" % time.ctime()
def register():
return "---register--welcome to our web time %s" % time.ctime()
def application(file_name):
if file_name == "/login.py":
return login()
elif file_name == "/register.py":
return register()
else:
return 'not found page'
浏览器请求的某个资源最终对应到你的框架里的某个函数 而不是对应服务器里面的某个功能
2---------------------------------
web服务器支持WSGI
else:
#2.2 如果以.py结尾 呢么就认为是动态资源的请求
env = dict()
env['PATH_INFO'] = file_name#字典 'PATH_INFO':'/index.py'
body = mini_frame.application(env,self.set_response_header())#传递一个字典和一个函数的引用
header = "HTTP/1.1 %s\r\n" % self.status
for temp in self.headers:
header += '%s:%s\r\n' %(temp[0],temp[1])
header += '\r\n'
response = header+body
#发送response给浏览器
new_socket.send(response.encode('utf-8'))
new_socket.close()
def set_response_header(self,status,headers):
self.status = status
self.headers = [('server','mini_web v8.8')]
self.headers += headers
简单模拟框架:
import time
def login():
return "---login--welcome to our web time %s" % time.ctime()
def register():
return "---register--welcome to our web time %s" % time.ctime()
def application(env,start_response):
start_response('200 OK',[('Content-Type', 'text/html;charset=utf-8')])
#start_response相当于是服务器里面的set_response_header函数 传递以上两个参数进去
file_name = env['PATH_INFO']
if file_name == "/login.py":
return login()
elif file_name == "/register.py":
return register()
else:
return 'not found page'
浏览器访问服务器 服务器把请求扔给框架 框架打开模板 框架打开数据库里的请求 查询数据 把独到的模版的信息和数据库查出的信息进行替换 最终组成一个body 调用服务器里面的函数 设置header 通过return把body返回去 服务器把header和body组合返回给浏览器
------------------------------