WEB框架本质
通常为B/S架构,浏览器作为客户端,服务器为服务端。优点:升级维护方便。
浏览器
功能:发送/解析请求(request)
请求格式
1)GET
GET请求格式 “GET / ?HTTP/1.1 ?\r\n” ??k1:v1\r\n ????????????? ??k2:v2\r\n 只有请求头,没有请求体
响应
特点:
- 没有请求体
- 数据必须在1K之内!
- GET请求数据会暴露在浏览器的地址栏中 —— 缺点
GET请求常用的操作:
- 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
- 点击页面上的超链接也一定是GET请求
- 提交表单时,表单默认使用GET请求,但可以设置为POST
2) POST
POST:请求格式 “POST / HTTP/1.1 \r\n” k1:v1\r\n ????????????? ???k2:v2\r\n 有请求头和请求体POST /index HTTP/1.1 ???????????Host: 127.0.0.1:8080 ???????????Connection: keep-alive ???????????Cache-Control: max-age=0 ???????????Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 ???????????User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36 ???????????HTTPS: 1 ???????????Accept-Encoding: gzip, deflate, sdch ???????????Accept-Language: zh-CN,zh;q=0.8 ???????????Cookie: csrftoken=hNmu2JOtntGMN0hSRSPmMQk2newEb3o8zb6pXW5Cc3m54IaA5VlTkUvqWsFezpni
200 OK ???????????Cache-Control:public, max-age=15 ???????????Connection:keep-alive ???????????Content-Encoding:gzip ???????????Content-Type:text/html; charset=utf-8 ???????????Date:Wed, 14 Jun 2017 01:21:17 GMT ???????????Expires:Wed, 14 Jun 2017 01:21:33 GMT ???????????Last-Modified:Wed, 14 Jun 2017 01:21:03 GMT ???????????Transfer-Encoding:chunked ???????????Vary:Accept-Encoding ???????????X-Frame-Options:SAMEORIGIN ???????????X-UA-Compatible:IE=10注意: 用户在页面看到的内容“字符串”(看到页面效果,由于浏览器解析)
响应:
Header
Body
HTTP
上面的GET、POST请求属于HTTP请求,浏览器和WEB服务端通信需要一个规则,这个规则就是HTTP协议:简单理解为规定消息格式。
特点:是无状态、短连接
自定义WEB框架
流程
A)自定义soket服务端,处理请求相关的数据 ——Wsgiref / uWSGI / Gunicorn
B)通过URL——>函数——>根据函数的逻辑(取数据)
C)把数据填充到HTML页面(字符串替换)
WEB框架分类
1.a、b、c都是自己的 Tornado
2.a用别人的,b、c用自己的 Django
3.a、c用别人的,b用自己的 Flask
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端
import socket ??def handle_request(client): ???buf = client.recv(1024) ???client.send("HTTP/1.1 200 OK\r\n\r\n") ???client.send("Hello, Seven") ??def main(): ???sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ???sock.bind((‘localhost‘,8000)) ???sock.listen(5) ??????while True: ???????connection, address = sock.accept() ???????handle_request(connection) ???????connection.close() ??if __name__ == ‘__main__‘: ???main()
上述通过socket来实现了其本质,而对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。我们需要在WSGI接口之上能进一步抽象,让我们专注于用一个函数处理一个URL,至于URL到函数的映射,就交给Web框架来做。
python标准库提供的独立WSGI服务器称为wsgiref。
from wsgiref.simple_server import make_server ???def RunServer(environ, start_response): ???start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) ???return [bytes(‘<h1>Hello, web!</h1>‘, encoding=‘utf-8‘), ] ???if __name__ == ‘__main__‘: ???httpd = make_server(‘‘, 8000, RunServer) ???print("Serving HTTP on port 8000...") ???httpd.serve_forever()
web请求生命周期
自定义web框架
import socketsk = socket.socket()sk.bind(("127.0.0.1", 8000))sk.listen(5)while True: ???conn, addr = sk.accept() ???data = conn.recv(8096) ???print(data) ?# data是浏览器传过来的请求信息,bytes类型 ???data_str = str(data, encoding="utf8") ???l1 = data_str.split("\r\n") ???l2 = l1[0].split() ???url = l2[1] ???# 根据url的不同,返回不同的内容 ???if url == "/index/": ???????body = "这是index页面" ???elif url == "/home/": ???????body = "这是home页面" ???else: ???????body = "404找不到" ???# 服务端回复消息 ???conn.send(bytes("HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n<h1>{}</h1>".format(body), encoding="utf8")) ???conn.close()
from wsgiref.simple_server import make_serverdef index(): ???with open("index.html", encoding="utf8") as f: ???????data = f.read() ???# 连接数据库 ???import pymysql ???# 连接 ???conn = pymysql.connect(host="localhost", user="root", password="root1234", database="s8", charset="utf8") ?# 没有- ???# 获取光标 ???cursor = conn.cursor() ???# 写sql语句 ???sql = "select name, pwd from userinfo where id =1;" ???cursor.execute(sql) ???ret = cursor.fetchone() ???print(ret) ???# 将数据库中的数据填充到HTML页面 ???new1_data = data.replace("@@2@@", ret[0]) ???new2_data = new1_data.replace("##3##", ret[1]) ???return new2_datadef home(): ???return "这是home页面"def login(): ???with open("login.html", encoding="utf8") as f: ???????data = f.read() ???import time ???time_str = str(time.time()) ???new_data = data.replace("@@2@@", time_str) ???return new_dataURL_FUNC = [ ???("/index/", index), ???("/home/", home), ???("/login/", login),]def run_server(environ, start_response): ???start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘)]) ?# 设置HTTP响应的状态码和头信息 ???url = environ[‘PATH_INFO‘] ?# 取到用户输入的url ???print("--->url:", url) ???# 根据url的不同,返回不同的内容 ???func_name = None ???for i in URL_FUNC: ???????if url == i[0]: ?# 如果能找到对应关系,就把函数名拿到 ???????????func_name = i[1] ???????????break ???# 拿到可以执行的函数,执行函数拿到结果 ???if func_name: ???????body = func_name() ???else: ???????body = "404找不到这个页面" ???return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]if __name__ == ‘__main__‘: ???httpd = make_server(‘‘, 8000, run_server) ???print("Serving HTTP on port 8000...") ???httpd.serve_forever()
from wsgiref.simple_server import make_serverimport jinja2def index(): ???with open("index.html", encoding="utf8") as f: ???????data = f.read() ???# 连接数据库 ???import pymysql ???# 连接 ???conn = pymysql.connect(host="localhost", user="root", password="root1234", database="s8", charset="utf8") ?# 没有- ???# 获取光标 ???cursor = conn.cursor() ???# 写sql语句 ???sql = "select name, pwd from userinfo where id =1;" ???cursor.execute(sql) ???ret = cursor.fetchone() ???print(ret) ???# 将数据库中的数据填充到HTML页面 ???new1_data = data.replace("@@2@@", ret[0]) ???new2_data = new1_data.replace("##3##", ret[1]) ???return new2_datadef home(): ???return "这是home页面"def userlist(): ???with open("userlist.html", encoding="utf8") as f: ???????data = f.read() ???# 生成了一个jinja2的模板对象 ???template = jinja2.Template(data) ???# 相当于字符串替换 ???new_data = template.render({ ???????"user_list": [ ???????????{"name": "jianchao", "pwd": "1234"}, ???????????{"name": "liyan", "pwd": "5678"} ???????] ???}) ???return new_datadef login(): ???with open("login.html", encoding="utf8") as f: ???????data = f.read() ???import time ???time_str = str(time.time()) ???new_data = data.replace("@@2@@", time_str) ???return new_dataURL_FUNC = [ ???("/index/", index), ???("/home/", home), ???("/login/", login), ???("/userlist/", userlist),]def run_server(environ, start_response): ???start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘)]) ?# 设置HTTP响应的状态码和头信息 ???url = environ[‘PATH_INFO‘] ?# 取到用户输入的url ???print("--->url:", url) ???# 根据url的不同,返回不同的内容 ???func_name = None ???for i in URL_FUNC: ???????if url == i[0]: ?# 如果能找到对应关系,就把函数名拿到 ???????????func_name = i[1] ???????????break ???# 拿到可以执行的函数,执行函数拿到结果 ???if func_name: ???????body = func_name() ???else: ???????body = "404找不到这个页面" ???return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]if __name__ == ‘__main__‘: ???httpd = make_server(‘‘, 9000, run_server) ???print("Serving HTTP on port 8000...") ???httpd.serve_forever()
<!DOCTYPE html><html lang="en"><head> ???<meta charset="UTF-8"> ???<meta http-equiv="X-UA-Compatible" content="IE=edge"> ???<meta name="viewport" content="width=device-width, initial-scale=1"> ???<title>index</title></head><body><h1>姓名:@@2@@</h1><h1>密码:##3##</h1></body></html>
<!DOCTYPE html><html lang="en"><head> ???<meta charset="UTF-8"> ???<meta http-equiv="X-UA-Compatible" content="IE=edge"> ???<meta name="viewport" content="width=device-width, initial-scale=1"> ???<title>Title</title> ???<link rel="stylesheet" href="bootstrap-3.3.7/css/bootstrap.min.css"></head><body><form action=""> ???<p>姓名<input type="text"></p> ???<p>密码<input type="password"></p> ???<p><input type="submit" value="登录"></p></form>@@2@@<script src="jquery-3.2.1.min.js"></script></body></html>
<!DOCTYPE html><html lang="zh-CN"><head> ?<meta charset="UTF-8"> ?<meta http-equiv="x-ua-compatible" content="IE=edge"> ?<meta name="viewport" content="width=device-width, initial-scale=1"> ?<title>Title</title></head><body> ???<ul> ???????{% for user in user_list %} ???????<li>{{user.name}}|{{user.pwd}}</li> ???????{% endfor %} ???</ul></body></html>
WEB框架
原文地址:https://www.cnblogs.com/huyangblog/p/8480651.html