【Django】Web框架本质
目录
原文: http://106.13.73.98/__/32/ @ 这样我们就可以自己实现Web框架了: from socket import * sk = socket(AF_INET,SOCK_STREAM) sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) sk.bind(('127.0.0.1',8080)) sk.listen() while True: conn,addr = sk.accept() data = conn.recv(9000) conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 conn.send(b'Hello,world!') conn.close() 可以说Web服务本质上都是在这十几行代码基础上扩展出来的,这段代码就是它们的祖宗。
让我们首先打印下我们在服务端接收到的消息是什么: from socket import * sk = socket(AF_INET,addr = sk.accept() data = conn.recv(9000) print(data) # 将浏览器发来的消息打印出来 conn.send(b'HTTP/1.1 200 OKrnrn') conn.send(b'Hello,world!') conn.close() 输出如下:
然后我们再看一个我们访问博客官网时浏览器收到的响应信息是什么,响应的相关信息可以在浏览器调试窗口的network标签页中看到: 我们发现收发的消息需要按照一定的格式来,这里就需要了解一下HTTP协议了。 每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。HTTP响应的Header中有一个==Content-Type==表明响应的内容格式。如==text/html==表示HTML网页. HTTP GET请求的格式: HTTP响应的格式: **** 根据不同的路径返回不同的内容普通版==思路:从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断.== from socket import * sk = socket(AF_INET,addr = sk.accept() data = conn.recv(8096) # 把收到的字节类型的数据转换成字符串 data_str = str(data,encoding='UTF-8') first_line = data_str.split('rn')[0] # 按rn分隔 url = first_line.split()[1] # 在按空格切割 conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 if url == '/index': response = 'index' elif url == '/home': response = 'home' else: response = '404 not found!' conn.send(bytes(response,encoding='UTF-8')) conn.close() 上面的代码解决了对于不同URL路径返回不同内容的需求。 函数版from socket import * sk = socket(AF_INET,8080)) sk.listen() # 将返回不同的内容部分封装成函数 def index(url): s = "这是%s页面!" % url return bytes(s,encoding='UTF-8') def home(url): s = "这是%s页面!" % url return bytes(s,encoding='UTF-8') while True: conn,encoding='UTF-8') first_line = data_str.split('rn')[0] # 按rn分隔 url = first_line.split()[1] # 在按空格切割 conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 if url == '/index': response = index(url) elif url == '/home': response = home(url) else: response = b'404 not found!' conn.send(response) conn.close() 看起来上面的代码还是要挨个写if判断,怎么办? 函数进阶版from socket import * sk = socket(AF_INET,encoding='UTF-8') # 定义一个url和实际要执行的函数的对应关系 url_list = [ ('/index',index),('/home',home) ] while True: conn,addr = sk.accept() data = conn.recv(8096) # 把收到的字节类型的数据转换成字符串 data_str = ?tr(data,encoding='UTF-8') first_line = data_str.split('rn')[0] # 按rn分隔 url = first_line.split()[1] # 在按空格切割 conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 # -------关键就在于这一坨代码------- func = None for i in url_list: if url == i[0]: func = i[1] break response = func(url) if func else b'404 not found!' conn.send(response) conn.close() 完美解决了不同URL返回不同内容的问题。 返回具体的HTML文件首先我们要知道:==不管是什么内容,最后都是转换成字节数据发送出去的.== from socket import * sk = socket(AF_INET,8080)) sk.listen() # 将返回不同的内容部分封装成函数 def index(url): with open('index.html','rb') as f: return f.read() def home(url): with open('home.html','rb') as f: return f.read() # 定义一个url和实际要执行的函数的对应关系 url_list = [ ('/index',home) ] while True: # ------------ 建立连接 接收消息 ------------ conn,addr = sk.accept() data = conn.recv(8096) # ------------ 对客服端发来的消息做处理 ------------ # 把收到的字节类型的数据转换成字符串 data_str = str(data,encoding='UTF-8') first_line = data_str.split('rn')[0] # 按rn分隔 url = first_line.split()[1] # 在按空格切割 # ------------ 业务逻辑处理部分 ------------ func = None for i in url_list: if url == i[0]: func = i[1] break response = func(url) if func else b'404 not found!' # ----------- 回复响应消息 ----------- conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 conn.send(response) conn.close() 没错,还有问题! 让网页动态起来==思路:使用字符串替换功能来实现这个需求.== login函数对应文件: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>login</title> </head> <body> <h1>登录页面</h1> <h1>This is login page!</h1> <a href="https://blog.csdn.net/qq_41964425/article/category/8083068" target="_blank">CSDN</a> <p>时间:@@[email?protected]@</p> <!--提前定义好特殊符号--> </body> </html> Python代码: from time import strftime from socket import * sk = socket(AF_INET,'rb') as f: return f.read() # 实现动态网页 def login(url): now_time = str(strftime('%F %T')) with open('login.html','r',encoding='UTF-8') as f: s = f.read() # 在网页中定义好特殊符号,用动态的数据去替换定义好的特殊符号 s = s.replace('@@[email?protected]@',now_time) return bytes(s,home),('/login',login),] while True: # ------------ 建立连接 接收消息 ------------ conn,encoding='UTF-8') first_line = data_str.split('rn')[0] # 按rn分隔 url = first_line.split()[1] # 在按空格切割 # ------------ 业务逻辑处理部分 ------------ func = None for i in url_list: if url == i[0]: func = i[1] break response = func(url) if func else b'404 not found!' # ----------- 回复响应消息 ----------- conn.send(b'HTTP/1.1 200 OKrnrn') # 响应状态行 conn.send(response) conn.close() 服务器和应用程序对于开发中的python web程序来说,一般会分为两部分:==服务器程序和应用程序.== 服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理;应用程序则负责具体的逻辑处理. 为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py等。不同的框架有不同的开发方式,但是无论如何,开发出来的应用程序都要和服务器程序配合,才能为用户提供服务。 如此,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论是对于服务器还是框架,都是不好的。 这时候,标准化就变得尤为重要,我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么它们就可以配合使用。一旦标准确定,双方各自实现。 WSGI(Web Server Gateway Interface)就是一个规范。它定义了使用Python编写的Web应用程序与Web服务器程序之间的接口格式,实现Web应用程序与Web服务器程序间的解耦. 常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,==Django开发环境正是使用这个模块来做服务器的.== wsgiref 模块使用wsgiref模块来替换我们自己写的Web框架的socket server部分: login函数对应文件: <!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-Type" charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>login</title> </head> <body> <h1>登录页面</h1> <h1>This is login page!</h1> <a href="https://blog.csdn.net/qq_41964425/article/category/8083068" target="_blank">CSDN</a> <p>时间:@@[email?protected]@</p> <!--提前定义好特殊符号--> </body> </html> Python代码: from time import strftime from wsgiref.simple_server import make_server # 将返回不同的内容部分封装成函数 def index(url): with open('index.html','rb') as f: return f.read() def login(url): """实现动态网页""" now_time = str(strftime('%F %T')) # 获取当前格式化时间 with open('login.html',encoding='UTF-8') as f: s = f.read() # 在网页中定义好特殊符号,用动态的数据去替换定义好的特殊符号 s = s.replace('@@[email?protected]@',] def run_server(environ,start_response): # 设置HTTP响应的状态码和头消息 start_response('200 OK',[('Content-Type','text/html;charset=utf8'),]) url = environ['PATH_INFO'] # 取到用户输入的url func = None for i in url_list: if url == i[0]: func = i[1] break response = func(url) if func else b'404 not found!' return [response,] if __name__ == '__main__': httpd = make_server('127.0.0.1',8080,run_server) print('Wsgiref has started...') httpd.serve_forever() 原文: http://106.13.73.98/__/32/ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |