目录
1.web框架理解
2.http工作原理
3.通过函数实现浏览器和服务端通信案例
4.服务器程序和引用程序理解
5.jinja2渲染模板案例
6.Django简单说明
Web框架的本质
web应用本质上就是一个socket服务端,而浏览器就是一个socket客户端,这样就可以实现web框架了
socket web服务器
import socket server = socket.socket() server.bind(('127.0.0.1',8000)) server.listen() while True: conn, addr = sk.accept() data = conn.recv(8096) conn.send(b"OK") conn.close()
http协议规定了浏览器发送消息或者服务器回复消息都要按照它规定来写
执行上面那段代码print(data)会得到以下结果
将 替换成换行后的结果 GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3355.4 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: csrftoken=CtHePYARJOKNx5oNVwxIteOJXpNyJ29L4bW4506YoVqFaIFFaHm0EWDZqKmw6Jm8
访问博客园返回浏览器的信息
由此可见首发信息都是按照一定格式来的,所以需要了解http协议工作模式
Http工作原理:
HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,
请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。 以下是 HTTP 请求/响应的步骤: 1. 客户端连接到Web服务器 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.luffycity.com。 2. 发送HTTP请求 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。 3. 服务器接受请求并返回HTTP响应 Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。 4. 释放连接TCP连接 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,
在该时间内可以继续接收请求; 5. 客户端浏览器解析HTML内容 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,
根据HTML的语法对其进行格式化,并在浏览器窗口中显示。 在浏览器地址栏键入URL,按下回车之后会经历以下流程: 1.浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址; 2.解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接; 2.浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器; 4.服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器; 5.释放 TCP连接; 6.浏览器将该 html 文本并显示内容;
http请求格式
http响应格式:
通过函数实现浏览器和服务端通信案例
自定义web框架按照http格式发送响应并根据url中的路径返回不同的内容
import socket server = socket.socket() server.bind(('127.0.0.1',8000)) server.listen() while True: conn,addr = server.accept() data = conn.recv(1024) data = data.decode('utf-8') print(data) url = data.split()[1] if url == '/home/': conn.send(b'HTTP/1.1 200 OK <h1>home<h1>') elif url == '/index/': conn.send(b'HTTP/1.1 200 OK <h1>index<h1>') else: conn.send(b'HTTP/1.1 200 OK <h1>404 not found<h1>') conn.close()
基于函数实现url不同路径返回不同内容
import socket server = socket.socket() server.bind(('127.0.0.1',8000)) server.listen() def func(url): s = f"this is {url} page" return bytes(s,encoding="utf-8") while True: conn,addr = server.accept() data = conn.recv(8096) data = str(data,encoding="utf-8") print(data) data1= data.split(" ")[0] url = data1.split()[1] conn.send(b'HTTP/1.1 200 OK <h1>ok<h1>') 这个地方需要注意的一个点 闭合标签不能写/ 否则就当成普通字符串进行处理 if url == "/index/": response = func(url) elif url == "/home/": response = func(url) else: response = b"404 not found" conn.send(response) conn.close()
实现url不同路径返回不同内容函数进阶版
import socket server =socket.socket() server.bind(('127.0.0.1',8000)) server.listen() def index(url): s = f"This is {url} page" return bytes(s,encoding="utf-8") def home(url): s = f"This is {url} page" return bytes(s,encoding="utf-8") list1 = [("/index/",index), ("/index/",home)] while True: conn,addr = server.accept() data = conn.recv(8096) data = str(data,encoding="utf-8") print(data) data1= data.split(" ")[0] url = data1.split()[1] conn.send(b'HTTP/1.1 200 OK <h1>ok<h1>') func = None for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found" conn.send(response) conn.close()
返回具体的html文件
import socket server =socket.socket() server.bind(('127.0.0.1',8000)) server.listen() def index(url): with open("template/index.html","r",encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") def home(url): with open("template/home.html", "r", encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") list1 = [("/index/",index), ("/home/",home)] while True: conn,addr = server.accept() data = conn.recv(8096) data = str(data,encoding="utf-8") print(data) data1= data.split(" ")[0] url = data1.split()[1] conn.send(b'HTTP/1.1 200 OK <h1>ok<h1>') func = None for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found" conn.send(response) conn.close()
网页动态
import socket server =socket.socket() server.bind(('127.0.0.1',8000)) server.listen() def index(url): with open("template/index.html","r",encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") def home(url): with open("template/home.html", "r", encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") def timer(url): import time with open("template/timer.html","r",encoding="utf-8") as f: s = f.read() s = s.replace('@@time@@',time.strftime("%Y-%m-%d %H:%M:%S")) return bytes(s,encoding="utf-8") list1 = [("/index/",index), ("/home/",home), ("/time/",timer)] while True: conn,addr = server.accept() data = conn.recv(8096) data = str(data,encoding="utf-8") print(data) data1= data.split(" ")[0] url = data1.split()[1] conn.send(b'HTTP/1.1 200 OK <h1>ok<h1>') func = None for item in list1: if item[0] == url: func = item[1] break if func: response = func(url) else: response = b"404 not found" conn.send(response) conn.close()
服务器程序和应用程序
对于真实开发中的python web程序来说,一般会分为服务器程序和应用程序
服务器程序负责对socket服务端进行封装,并在请求到来时,对请求的各种数据进行处理
应用程序则负责处理具体的逻辑,为了方便应用程序开发,就出现了众多的web框架。
应用程序必须和服务程序配合才能为用户提供服务。
WSGI (Web Server Gateway Interface)是一种规范,定义了使用Python编写的Web应用程序与web服务程序之间的接口格式,实现了web应用程序和web服务程序间的解耦
常用的WSGI服务器有uWSGI、Gunicorn、而python标准库提供的WSGI叫wsgiref,Django开发环境用的就是这个模块来做的服务器。
wsgiref写web框架的socket server例子:
from wsgiref.simple_server import make_server def index(url): with open("template/index.html","r",encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") def home(url): with open("template/home.html", "r", encoding="utf-8") as f: s = f.read() return bytes(s,encoding="utf-8") def timer(url): import time with open("template/timer.html","r",encoding="utf-8") as f: s = f.read() s = s.replace('@@time@@',time.strftime("%Y-%m-%d %H:%M:%S")) return bytes(s,encoding="utf-8") list1 = [("/index/",index), ("/home/",home), ("/time/",timer)] # def run_server(environ,start_response): start_response('200 ok',[('Content-Type','text/html;charset=utf8'),]) url =environ['PATH_INFO'] func =None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b'404 not found' return [response,] if __name__ == '__main__': httpd = make_server('127.0.0.1',8000,run_server) print("I am waitting for you at 8000") httpd.serve_forever()
使用jinja2渲染
python代码 from wsgiref.simple_server import make_server from jinja2 import Template def index(url): with open('template/index2.html',"r",encoding="utf-8") as f: data = f.read() template = Template(data) #生成模板 #把数据填充到模板中 ret = template.render({'name': 'xxx', 'hobby_list': ['抽烟', '喝酒', '烫头']}) return bytes(ret,encoding="utf-8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") list1 = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息 url = environ['PATH_INFO'] # 取到用户输入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
要渲染的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> <h1>姓名:{{name}}</h1> <h1>爱好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
Django简介
安装 pip3 install django==1.11.22
创建一个Django项目
django-admin startproject mysite02
目录简介
mysite/ ├── manage.py # 管理文件 └── mysite # 项目目录 ├── __init__.py ├── settings.py # 配置 ├── urls.py # 路由 --> URL和函数的对应关系 └── wsgi.py # runserver命令就使用wsgiref模块做简单的web server
运行django项目
python manage.py runserver 127.0.0.1:8000
模板文件配置
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, "template")], # template文件夹位置 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
静态文件配置
STATIC_URL = '/static/' # HTML中使用的静态文件夹前缀 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), # 静态文件存放位置 ]
方便提交表单暂时禁用csrf中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Django基础三要素
from django.shortcuts import HttpResponse, render, redirect
HttpResponse 内部传入一个字符串参数,返回给浏览器
def index(request): # 业务逻辑代码 return HttpResponse("OK")
render
除request参数外还接受一个待渲染的模板和一个保存具体数据的字典参数
将数据填充进模板文件,最后把结果返回给浏览器(类似上面的jinja2)
def index(request): # 业务逻辑代码 return render(request, "index.html", {"name": "xxx", "hobby": ["烫头", "泡吧"]})
redirect
接收一个URL参数,表示跳转到指定的URL
def index(request): # 业务逻辑代码 return redirect("/home/")
此博客大部分内容是参考老师的,主要为了自己加深理解......