http协议简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。
HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。
http协议特性
(1) 基于TCP/IP
http协议是基于TCP/IP协议之上的应用层协议
(2) 基于请求-响应模式
HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并 返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应
(3) 无状态保存
HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个 级别,协议对于发送过的请求或响应都不做持久化处理。你连接我一次,我响应一次就断开了
(4)无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
请求协议格式:
大前提:字符串/字节
请求首行 请求方式 url (路径?get请求参数) 协议/版本号
请求头 key:value
请求体 数据(只有post请求才会有请求体)
换行: 请求头与请求体之间用
响应协议格式:
响应首行 协议/版本号 状态码 状态码译文
响应头 Content-Type:text/html key:value
响应体 <h1>hello</h> 这才是客服端浏览器上显示的东西
换行: 响应头与响应体之间用
web框架本质
大家应该都晓得,所有web应用,本质上就是一个socket服务端,用户浏览器就是一个socket客服端
下面简单的模拟socket举个例子
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 7 def handle_request(client): 8 data = client.recv(8096) 9 print(data.decode('utf8')) 10 client.send("HTTP/1.1 200 OK ".encode('utf8')) 11 client.send("Hello WeiSuoJun".encode('utf8')) 12 13 14 def main(): 15 sock = socket.socket() 16 sock.bind(('localhost', 9999)) 17 sock.listen(5) 18 19 while True: 20 conn, addr = sock.accept() 21 handle_request(conn) 22 conn.close() 23 24 25 if __name__ == '__main__': 26 main()
后边为了方便的开发,大堆的web框架出来了,但是各种框架开发模式应该有所不同,不管咋样最终要开发出的应用程序都要和服务器配合,才能够给用户提供服务,这样服务器程序就要为不同的框架提供不同的支持,这就意味着一片混乱来了,咋能克服混乱局面,大家商量好这套标准。WSGI就诞生了、一套套规范,定义了一些web app与web server之间接口的格式,主要就是实现两者之间的解耦,Python中标准库提供的独立WSGI服务器叫wsgiref这个模块,本质就是socket服务端。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from wsgiref.simple_server import make_server 5 6 def RunServer(environ, start_response): 7 print(environ) 8 start_response('200 OK', [('Content-Type', 'text/html')]) 9 return [bytes('<h1>Hello, WeiSuoJun!</h1>', encoding='utf-8'), ] 10 11 12 if __name__ == '__main__': 13 httpd = make_server('127.0.0.1', 9999, RunServer) 14 print("Serving HTTP on port 9999...") 15 httpd.serve_forever()
environ请求所有相关信息
基于socket模拟web框架的斗笔行为(web250框架)
(静态页面)实现的思想:等待用户进来连接,收到请求的数据,对数据(字节转字符串)进行分割,拿到请求url走对应的函数(若没有函数进行匹配就返回404),(暂且还没的视图这么一说),在对应的函数(暂且还没得视图这么一说)里边做打开文件操作,然后返回给用户。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 7 def f1(request): 8 f = open('index.html', 'rb') 9 data = f.read() 10 f.close() 11 return data 12 13 14 def f2(request): 15 f = open('article.html', 'rb') 16 data = f.read() 17 f.close() 18 return data 19 20 21 routers = [ 22 ('/xxxx', f1), 23 ('/oooo', f2), 24 ] 25 26 27 def run(): 28 sock = socket.socket() 29 sock.bind(("127.0.0.1", 8080)) 30 sock.listen(5) 31 32 while True: 33 conn, addr = sock.accept() 34 data = conn.recv(8096) 35 data = str(data, encoding='utf8') 36 headers, bodys = data.split(' ') 37 temp_list = headers.split(' ') 38 method, url, protocal = temp_list[0].split(' ') 39 conn.send(b"HTTP/1.1 200 OK ") 40 41 func_name = None 42 for item in routers: 43 if item[0] == url: 44 func_name = item[1] 45 break 46 if func_name: 47 response = func_name(data) 48 else: 49 response = b"404" 50 51 conn.send(response) 52 53 conn.close() 54 55 56 if __name__ == '__main__': 57 run()

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <h1>用户登录</h1> 9 <form action=""> 10 <p><input type="text" placeholder="用户名"></p> 11 <p><input type="text" placeholder="密码"></p> 12 <p><input type="submit" value="提交"></p> 13 </form> 14 </body> 15 </html>

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <table border="1"> 9 <thead> 10 <tr> 11 <th>id</th> 12 <th>用户名</th> 13 <th>邮箱</th> 14 </tr> 15 </thead> 16 <tbody> 17 <tr> 18 <th>1</th> 19 <th>@root@</th> 20 <th>root@qq.com</th> 21 </tr> 22 </tbody> 23 </table> 24 </body> 25 </html>
(动态页面)实现思想:只是在静态的基础上,通过pymysql模块连接数据库,拿到数据然后使用jinja2对模板的渲染,然后返回给用户。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import socket 5 6 7 def f1(request): 8 f = open('index.html', 'rb') 9 data = f.read() 10 f.close() 11 return data 12 13 14 def f2(request): 15 f = open('article.html', 'r', encoding='utf8') 16 data = f.read() 17 f.close() 18 import time 19 ctime = time.ctime() 20 data = data.replace('@root@', str(ctime)) 21 return data.encode('utf8') 22 23 24 def f3(request): 25 import pymysql 26 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='', db='db2') 27 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) 28 cursor.execute("select id,name,extra from users") 29 user_list = cursor.fetchall() 30 cursor.close() 31 conn.close() 32 print(user_list) 33 34 f = open('userinfo.html', 'r', encoding='utf8') 35 data = f.read() 36 f.close() 37 38 # 专门来渲染模板 39 from jinja2 import Template 40 template = Template(data) 41 data = template.render(user_list=user_list, name='搞大佬') 42 print(data) 43 return data.encode('utf8') 44 45 46 routers = [ 47 ('/xxxx', f1), 48 ('/oooo', f2), 49 ('/yyyy', f3), 50 ] 51 52 53 def run(): 54 sock = socket.socket() 55 sock.bind(("127.0.0.1", 13333)) 56 sock.listen(5) 57 58 while True: 59 conn, addr = sock.accept() 60 data = conn.recv(4096) 61 data = str(data, encoding='utf8') 62 headers, bodys = data.split(' ') 63 temp_list = headers.split(' ') 64 method, url, protocal = temp_list[0].split(' ') 65 conn.send(b"HTTP/1.1 200 OK ") 66 67 func_name = None 68 for item in routers: 69 if item[0] == url: 70 func_name = item[1] 71 break 72 if func_name: 73 response = func_name(data) 74 else: 75 response = b"404" 76 77 conn.send(response) 78 79 conn.close() 80 81 82 if __name__ == '__main__': 83 run()
index.html与article.html与上边相同

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <table border="1"> 9 <thead> 10 <tr> 11 <th>id</th> 12 <th>用户名</th> 13 <th>描述</th> 14 </tr> 15 </thead> 16 <tbody> 17 {% for row in user_list %} 18 <tr> 19 <td>{{ row.id }}</td> 20 <td>{{ row.name }}</td> 21 <td>{{ row.extra }}</td> 22 </tr> 23 {% endfor %} 24 </tbody> 25 {{ name }} 26 </table> 27 </body> 28 </html>
实现的效果如图:
总结:
1.http 无状态 短连接
2.浏览器(socket客服端)
网站(socket服务端)
3.自己搞网站
a.socket服务端
b.根据url不同返回不同的内容
路由系统: url---->函数(视图函数)
c.字符串返回给用户
模板引擎渲染:html充当模板(特殊字符)
当然自己可以任意数据
字符串
4.web框架
a,b,c ------------------------------->Tornado
[第三方a],b,c ------------------------------->wsgiref ---->Django
[第三方a],b,[第三方c]---------------------------->werkzurg--->Flask