django基础
HTTP 超文本传输协议 是在应用层 如今广泛使用的是HTTP1.1 默认为80端口
5层协议:
HTTP协议 应用层
TCP/UDP协议 运输层
IP 网络层
数据链路层
物理层
HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
请求、响应的步骤
1 客户端连接到web服务器(创建连接)
2 发送HTTP请求(get/post方式)
请求报文由请求行、请求头、空行、请求数据组成
3 服务器接受请求并返回HTTP响应
响应首行(状态行)、响应头部、空行和响应数据4部分组成
4 释放连接TCP连接
5 客户端浏览器解析响应体内容
URL 统一资源定位符
超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:
(1)传送协议。
(2)层级URL标记符号(为[//],固定不变)
(3)访问资源需要的凭证信息(可省略)
(4)服务器。(通常为域名,有时为IP地址)
(5)端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
(6)路径。(以“/”字符区别路径中的每一个目录名称)
(7)查询。(GET模式的请求参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)
以http://www.baidu.com:80/news/index.html?id=250&page=1 为例, 其中:
http : 是协议;
www.baidu.com: 是服务器(域名);
80:是服务器上的网络端口号;
/news/index.html,是路径;
?id=250&page=1,是查询(携带参数)。
以?区别路径和参数,参数使用键值对方式name=’zs’&age=10,每个键值对使用&符号链接。
响应首行(状态行)分析:
HTTP/1.1 200 OK
包含 协议–>>HTTP/1.1, 响应码(状态码)—>>200 , 状态码描述—>>OK
状态码:
200: 服务器很好的处理了客户端的请求,一切 OK
302: 重定向 这里面发生了2次请求
304:通常表示资源文件在服务器没有更改,而浏览器端又有缓存,这时候回送 304 状体码通知浏览器拿本地的缓存显示
404:表示客户端访问的资源路径有问题或者资源问题不存在
500:表示服务器出现了 异常.
响应头部分析:
server: Apache-Coyote/1.1—>> 服务器版本号
Set-Cookie: JSESSIONID=ECA8005D1235BBB6B9CFCC338A8206FD;
Path=/03test; HttpOnly学cookie时在讲
Content-Type: text/html;charset=ISO-8859-1响应字符集,告诉浏览器以什么样的字符集解码;
3、Content-Length: 265 响应体长度
4、Date: Fri, 23 Jun 2017 13:45:01 GMT 发送日期 少8个小时;
5、Expires: -1、Cache-control:no-cache、Pragma:no-cache 三个响应头一起使用, 表示禁止浏览器缓存当前页面. 每个浏览器厂商对认识的禁止头不同因此三 个一起使用。
客户端服务器概念
客户端:就是我们常用的程序例如qq、微信,浏览器等等。
服务器:要一直运行着给别人提供服务的机器。
例如现在我使用的CTS软件给同学们提供服务,我的电脑就是服务端(服务器)
C/S架构
C/S即:Client与Server ,中文意思:客户端与服务器端架构。
这里的客户端一般泛指客户端应用程序exe,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。
备注:
例如我们电脑上安装的程序,就属于C/S架构 ,软件程序一旦运行,就需要客户端和服务器端持续不间断的进行交互,对电脑的硬件要求比较高,(例如吃鸡的话,就对电脑的内存,内核,耳机等都有很高的要求)
B/S架构
B/S即:Browser与Server,中文意思:浏览器端与服务器端架构。
只需在浏览器上通过HTTP去请求服务器端相关的资源(网页资源)。
备注:不会一直交互,浏览器与服务器的交互不是持续性的,他的方式是交互断开,再交互,再断开这样的一个过程,详情可以参考socket服务,交互之间需要经历三次握手,四次挥手的过程,对硬件要求不高
web框架
程序中的框架:其实程序中的框架也类似于我们生活中的框架,它就像我们盖楼时的楼房的构架,盖好之后就可以实现一些房子的基本功能,还需要我们装修才能入住
程序中的框架可以完成一些基本的工作,程序员在此功能的基础上来开发实现自己的业务功能,把程序员从繁琐的重复性的代码中解脱出来,提交开发效率;
web框架的本质
我们可以这样理解:所有的Web应用框架本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 一些常用框架(Django、Tornado、Flash)是对socket服务端进行的封装,使得基础功能更加完善。
自定义框架格式
import socket
server_sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(("127.0.0.1",9999))
server_sk.listen(128)
while True:
print("等待客户端的连接:")
new_sk, addr = server_sk.accept()
content = new_sk.recv(1024)# 默认是二进制内容
content = content.decode("utf-8") #解码
print("接收到了数据")
print(content) # 接收到的内容是请求报文
# 给浏览器发送内容
msg1 = "HTTP/1.1 200 OK\r\n".encode("utf-8") #设置响应首行
msg2 = "Content-Type:text/html;charset=utf-8\r\n".encode("utf-8") #s设置响应头
# 告诉浏览器返回的是文本类型的html,并以utf-8编码进行解码
msg3 = "\r\n".encode("utf-8") #响应空行
msg4 = "北方有佳人,自挂东南枝".encode("utf-8") #设置响应体
new_sk.send(msg1)
new_sk.send(msg2)
new_sk.send(msg3)
new_sk.send(msg4)
new_sk.close()
notice:如何解决返回给浏览器中的中文乱码问题
写完自定义框架之后我们可以打开设置的地址127.0.0.1:9999
根据不同路径返回不同的内容
接下来我们把这个基础的自定义框架进行优化,让它可以根据不同的路径返回不同的内容:
import socket
server_sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(("127.0.0.1",9999))
server_sk.listen(128)
while True:
client_sk,addrs = server_sk.accept()
content = client_sk.recv(1024).decode("utf-8")
print("客户端发来贺电:")
print(content)
header_lst = content.split("\r\n")
print(header_lst)
title_lst = header_lst[0].split(" ")
print(title_lst)
path = title_lst[1]
print(path)
if path == "/home":
msg = "这是{}界面".format(path).encode("utf-8")
elif path == "/index":
msg = "this is {} page".format(path).encode("utf-8")
else:
msg = "sorry 404 not found...".format(path).encode("utf-8")
# 给浏览器发送内容
msg1 = "HTTP/1.1 200 OK\r\n".encode("utf-8") # 设置响应首行
msg2 = "Content-Type:text/html;charset=utf-8\r\n".encode("utf-8") # s设置响应头
# 告诉浏览器返回的是文本类型的html,并以utf-8编码进行解码
msg3 = "\r\n".encode("utf-8") # 响应空行
# msg4 = "北方有佳人,自挂东南枝".encode("utf-8") # 设置响应体
client_sk.send(msg1)
client_sk.send(msg2)
client_sk.send(msg3)
client_sk.send(msg)
client_sk.close()
上面的代码解决了不同URL路径返回不同内容的需求。
返回HTML的内容
完美解决了不同URL返回不同内容的问题。 但是我不想仅仅返回几个字符串,我想给浏览器返回完整的HTML内容,这又该怎么办呢?
没问题,不管是什么内容,最后都是转换成字节数据发送出去的。 我们可以打开HTML文件,读取出它内部的二进制数据,然后再发送给浏览器。
import socket
def home(path):
with open("home.html",mode="r",encoding="utf-8") as f:
msg = f.read()
msg = msg.replace("xxx",path).encode("utf-8")
return msg
def index(path):
with open("index.html",mode="rb") as f:
msg = f.read()
return msg
def error(path):
with open("error.html",mode="rb") as f:
msg = f.read()
return msg
url_list = [
('/index',index),
('/home',home)
]
server_sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(("127.0.0.1",9999))
server_sk.listen(128)
while True:
client_sk,addrs = server_sk.accept()
content = client_sk.recv(1024).decode("utf-8")
print("客户端发来贺电:")
print(content)
header_lst = content.split("\r\n")
print(header_lst)
title_lst = header_lst[0].split(" ")
print(title_lst)
path = title_lst[1] # 获取地址中的路径
print(path)
function = None
for url_tup in url_list:
if url_tup[0] == path:
function = url_tup[1]
if function:
msg = function(path)
else:
msg = error(path)
# 给浏览器发送内容
msg1 = "HTTP/1.1 200 OK\r\n".encode("utf-8") # 设置响应首行
msg2 = "Content-Type:text/html;charset=utf-8\r\n".encode("utf-8") # s设置响应头
# 告诉浏览器返回的是文本类型的html,并以utf-8编码进行解码
msg3 = "\r\n".encode("utf-8") # 响应空行
# msg4 = "北方有佳人,自挂东南枝".encode("utf-8") # 设置响应体
client_sk.send(msg1)
client_sk.send(msg2)
client_sk.send(msg3)
client_sk.send(msg)
client_sk.close()
备注:在其中可以使用
msg = msg.replace("xxx",path).encode("utf-8")
来实现页面的动态交互
WSGI
刚才我们已经分析了Django框架,Django框架是应用程序,负责业务逻辑,本身没有服务器程序功能。现有有很多优秀的服务器程序 例如 uwsgi、Gunicorn。而Web应用框架和服务器程序进行配合使用就需要遵循一定的规范
服务器和应用框架都遵循了WSGI协议后,就可以任意组合了更加灵活。
而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。