Django之web框架的本质

web框架的本质及自定义web框架

 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响应,按照http协议的请求协议发送请求,服务端按照http协议的响应协议来响应请求,这样的网络通信,我们就可以自己实现Web框架了。

简单的web框架
创建一个python文件,内容如下,名称为test.py
(day53)
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()
conn,addr = sk.accept()
from_b_msg = conn.recv(1024)
str_msg = from_b_msg.decode('utf-8')
#socket是应用层和传输层之间的抽象层,每次都有协议,协议就是消息格式,那么传输层的消息格式我们不用管,因为socket帮我们搞定了,但是应用层的协议还是需要咱们自己遵守的,所以再给浏览器发送消息的时候,如果没有按照应用层的消息格式来写,那么你返回给浏览器的信息,浏览器是没法识别的。而应用层的协议就是我们的HTTP协议,所以我们按照HTTP协议规定的消息格式来给浏览器返回消息就没有问题了,关于HTTP我们会细说,首先看一下直接写conn.send(b'hello')的效果,然后运行代码,通过浏览器来访问一下,然后再看这一句conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello')的效果
#下面这句就是按照http协议来写的
# conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello')
#上面这句还可以分成下面两句来写
conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
conn.send(b'hello')
浏览器发送的请求:

1673920-20190722172011855-750922745.png

目前还没有写如何返回一个HTML文件给浏览器,点开127.0.0.1看看:

1673920-20190722172122844-1823168130.png

在python文件中打印一下浏览器发过来的请求信息:

1673920-20190722172200723-765829400.png

重新启动代码,在网址中输入:

1673920-20190722172224049-194889022.png

在重新启动代码,在网址中输入:

1673920-20190722172253689-631150240.png

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连接;
  3. 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
  4. 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
  5. 释放 TCP连接;
  6. 浏览器将该 html 文本并显示内容;  

http协议特点

1.基于 请求(request)-响应(response) 的模式

        HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并 返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应
2.无状态保存HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个 级别,协议对于发送过的请求或响应都不做持久化处理。使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成 如此简单的。可是,随着Web的不断发展,因无状态而导致业务处理变得棘手 的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的 其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,需要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能, 于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管 理状态了。有关Cookie的详细内容稍后讲解。
3.无连接  无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间,并且可以提高并发性能,不能和每个用户建立长久的连接,请求一次相应一次,服务端和客户端就中断了。但是无连接有两种方式,早期的http协议是一个请求一个响应之后,直接就断开了,但是现在的http协议1.1版本不是直接就断开了,而是等几秒钟,这几秒钟是等什么呢,等着用户有后续的操作,如果用户在这几秒钟之内有新的请求,那么还是通过之前的连接通道来收发消息,如果过了这几秒钟用户没有发送新的请求,那么就会断开连接,这样可以提高效率,减少短时间内建立连接的次数,因为建立连接也是耗时的,默认的好像是3秒中现在,但是这个时间是可以通过咱们后端的代码来调整的,自己网站根据自己网站用户的行为来分析统计出一个最优的等待时间。

http请求方法

请求方式:get 和 post
GET提交的数据会放在URL之后,也就是请求行里面,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456.(请求头里面那个content-type做的这种参数形式,后面讲) POST方法是把提交的数据放在HTTP包的请求数据部分中.
GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
GET与POST请求在服务端获取请求数据方式不同,就是我们自己在服务端取请求数据的时候的方式不同了
常用的get请求方式:浏览器输入网址 ,a标签 ,form标签 method='get'
post请求方法,一般都用来提交数据.比如用户名密码登录
其他方法:
与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。

PUT

向指定资源位置上传其最新内容。

DELETE

请求服务器删除Request-URI所标识的资源。

TRACE

回显服务器收到的请求,主要用于测试或诊断。

OPTIONS

这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用'*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。

CONNECT

这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用'*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。

http响应状态码

1xx消息——请求已被服务器接收,继续处理
2xx成功——请求已成功被服务器接收、理解、并接受
3xx重定向——需要后续操作才能完成这一请求
4xx请求错误——请求含有词法错误或者无法被执行
5xx服务器错误——服务器在处理某个正确请求时发生错误

URL

超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:

  • 传送协议。
  • 层级URL标记符号(为[//],固定不变)
  • 访问资源需要的凭证信息(可省略)
  • 服务器。(通常为域名,有时为IP地址)
  • 端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
  • 路径。(以“/”字符区别路径中的每一个目录名称)
  • 查询。(GET模式的窗体参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)
  • 片段。以“#”字符为起点
              以http://www.luffycity.com:80/news/index.html?id=250&page=1 为例, 其中:http,是协议;www.luffycity.com,是服务器;80,是服务器上的默认网络端口号,默认不显示;/news/index.html,是路径(URI:直接定位到对应的资源);?id=250&page=1,是查询。大多数网页浏览器不要求用户输入网页中“http://”的部分,因为绝大多数网页内容是超文本传输协议文件。同样,“80”是超文本传输协议文件的常用端口号,因此一般也不必写明。一般来说用户只要键入统一资源定位符的一部分(www.luffycity.com:80/news/index.html?id=250&page=1)就可以了。
    由于超文本传输协议允许服务器将浏览器重定向到另一个网页地址,因此许多服务器允许用户省略网页地址中的部分,比如 www。从技术上来说这样省略后的网页地址实际上是一个不同的网页地址,浏览器本身无法决定这个新地址是否通,服务器必须完成重定向的任务。

http请求和相应格式格式

请求  和   响应请求格式GET / HTTP/1.1  ---  GET /clschao/articles/9230431.html?name=chao&age=18 HTTP/1.1User-Agent:....xx:xx请求数据  get请求方法没有请求数据  post请求数据方法的请求数据放在这里响应格式HTTP/1.1 200 okkl:v1k2:v2响应数据

返回HTML文件的web框架

写一个html文件,名称为test.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="test.css"><!--加上下面这句,那么我们看浏览器调试窗口中的那个network里面就没有那个favicon.ico的请求了,其实这就是页面title标签文字左边的那个页面图标,但是这个文件是我们自己本地的,所以我们需要在后端代码里面将这个文件数据读取出来返回给前端--><link rel="icon" href="wechat.ico"><!--直接写在html页面里面的css样式是直接可以在浏览器上显示的--><!--<style>--><!--h1{--><!--background-color: green;--><!--color: white;--><!--}--><!--</style>-->
</head>
<body><h1>姑娘,你好,我是Jaden,请问约吗?嘻嘻~~</h1>
<!--直接写在html页面里面的img标签的src属性值如果是别人网站的地址(网络地址)是直接可以在浏览器上显示的-->
<!--<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1550395461724&di=c2b971db12eef5d85aba410d1e2e8568&imgtype=0&src=http%3A%2F%2Fy0.ifengimg.com%2Fifengimcp%2Fpic%2F20140822%2Fd69e0188b714ee789e97_size87_w800_h1227.jpg" alt="">--> <!--如果都是网络地址,那么只要你的电脑有网,就可以看到,不需要自己在后端写对应的读取文件,返回图片文件信息的代码,因为别人的网站就做了这个事情了-->
<img src="meinv.png" alt="" width="100" height="100"> <!--如果你是本地的图片想要返回给页面,你需要对页面上的关于这个图片的请求要自己做出响应,这个src就是来你本地请求这个图片,你只要将图片信息读取出来,返回给页面,页面拿到这个图片的数据,就能够渲染出来了,是不是很简单--><!--直接写在html页面里面的js操作是直接可以在浏览器上显示的-->
<!--<script>--><!--alert('这是我们第一个网页')-->
<!--</script>--><script src="test.js"></script>
</body>
</html>
服务端程序,文件名称为test.py:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()
conn,addr = sk.accept()
from_b_msg = conn.recv(1024)
str_msg = from_b_msg.decode('utf-8')
print('浏览器请求信息:',str_msg)# conn.send(b'HTTP/1.1 200 ok \r\ncontent-type:text/html;charset=utf-8;\r\n') 
conn.send(b'HTTP/1.1 200 ok \r\n\r\n')with open('test1.html','rb') as f:f_data = f.read()
conn.send(f_data)

返回静态文件的高级web框架

还是使用第一个web框架的html文件,只需要写一些服务端程序:
import socketsk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()#首先浏览器相当于给我们发送了多个请求,一个是请求我们的html文件,而我们的html文件里面的引入文件的标签又给我们这个网站发送了请求静态文件的请求,所以我们要将建立连接的过程循环起来,才能接受多个请求,没毛病
while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')#通过http协议我们知道,浏览器请求的时候,有一个请求内容的路径,通过对请求信息的分析,这个路径我们在请求的所有请求信息中可以提炼出来,下面的path就是我们提炼出来的路径path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')#由于整个页面需要html、css、js、图片等一系列的文件,所以我们都需要给人家浏览器发送过去,浏览器才能有这些文件,才能很好的渲染你的页面#根据不同的路径来返回响应的内容if path == '/': #返回html文件print(from_b_msg)with open('test.html','rb') as f:# with open('Python开发.html','rb') as f:data = f.read()conn.send(data)conn.close()elif path == '/meinv.png': #返回图片with open('meinv.png','rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()elif path == '/test.css': #返回css文件with open('test.css','rb') as f:css_data = f.read()conn.send(css_data)conn.close()elif path == '/wechat.ico':#返回页面的ico图标with open('wechat.ico','rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()elif path == '/test.js': #返回js文件with open('test.js','rb') as f:js_data = f.read()conn.send(js_data)conn.close()#注意:上面每一个请求处理完之后,都有一个conn.close()是因为,HTTP协议是短链接的,一次请求对应一次响应,这个请求就结束了,所以我们需要写上close,不然浏览器自己断了,你自己写的服务端没有断,就会出问题。

函数版高级web框架

还是使用第一个web框架的html文件,只需要写一些服务端程序:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2019/2/17 14:06
# @Author  : wuchao
# @Site    :
# @File    : test.py
# @Software: PyCharm
import socketsk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()#处理页面请求的函数
def func1(conn):with open('test.html', 'rb') as f:# with open('Python开发.html','rb') as f:data = f.read()conn.send(data)conn.close()#处理页面img标签src属性值是本地路径的时候的请求
def func2(conn):with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()
#处理页面link( <link rel="stylesheet" href="test.css">)标签href属性值是本地路径的时候的请求
def func3(conn):with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()#处理页面link(<link rel="icon" href="wechat.ico">)标签href属性值是本地路径的时候的请求
def func4(conn):with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()#处理页面script(<script src="test.js"></script>)标签src属性值是本地路径的时候的请求
def func5(conn):with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':func1(conn)elif path == '/meinv.png':func2(conn)elif path == '/test.css':func3(conn)elif path == '/wechat.ico':func4(conn)elif path == '/test.js':func5(conn)

更高级(多线程版)web框架

应用上并发编程内容html文件和静态文件都直接给浏览器,html文件和静态文件还是上面的
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2019/2/17 14:06
# @Author  : wuchao
# @Site    : 
# @File    : test.py
# @Software: PyCharm
import socket
from threading import Thread
#注意一点,不开多线程完全是可以搞定的,在这里只是教大家要有并发编程的思想,所以我使用了多线程sk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()def func1(conn):with open('test.html', 'rb') as f:# with open('Python开发.html','rb') as f:data = f.read()conn.send(data)conn.close()def func2(conn):with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()def func3(conn):with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()def func4(conn):with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()def func5(conn):with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()while 1:conn,addr = sk.accept()# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)conn.send(b'HTTP/1.1 200 ok \r\n\r\n')print(from_b_msg)if path == '/':# func1(conn)t = Thread(target=func1,args=(conn,))t.start()elif path == '/meinv.png':# func2(conn)t = Thread(target=func2, args=(conn,))t.start()elif path == '/test.css':# func3(conn)t = Thread(target=func3, args=(conn,))t.start()elif path == '/wechat.ico':# func4(conn)t = Thread(target=func4, args=(conn,))t.start()elif path == '/test.js':# func5(conn)t = Thread(target=func5, args=(conn,))t.start()

更更高级版web框架

if判断太多,开线程方式也比较麻烦有多少个if判断,就写多少次创建线程,简化一下:
import socket
from threading import Threadsk = socket.socket()
sk.bind(('127.0.0.1',8001))
sk.listen()def func1(conn):conn.send(b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n')with open('test.html', 'rb') as f:# with open('Python开发.html','rb') as f:data = f.read()conn.send(data)conn.close()def func2(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('meinv.png', 'rb') as f:pic_data = f.read()# conn.send(b'HTTP/1.1 200 ok \r\n\r\n')conn.send(pic_data)conn.close()def func3(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('test.css', 'rb') as f:css_data = f.read()conn.send(css_data)conn.close()def func4(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('wechat.ico', 'rb') as f:ico_data = f.read()conn.send(ico_data)conn.close()def func5(conn):conn.send(b'HTTP/1.1 200 ok\r\n\r\n')with open('test.js', 'rb') as f:js_data = f.read()conn.send(js_data)conn.close()#定义一个路径和执行函数的对应关系,不再写一堆的if判断了
l1 = [('/',func1),('/meinv.png',func2),('/test.css',func3),('/wechat.ico',func4),('/test.js',func5),
]#遍历路径和函数的对应关系列表,并开多线程高效的去执行路径对应的函数,
def fun(path,conn):for i in l1:if i[0] == path:t = Thread(target=i[1],args=(conn,))t.start()# else:#     conn.send(b'sorry')while 1:conn,addr = sk.accept()#看完这里面的代码之后,你就可以思考一个问题了,很多人要同时访问你的网站,你在请求这里是不是可以开起并发编程的思想了,多进程+多线程+协程,妥妥的支持高并发,再配合服务器集群,这个网页就支持大量的高并发了,有没有很激动,哈哈,但是咱们写的太low了,而且功能很差,容错能力也很差,当然了,如果你有能力,你现在完全可以自己写web框架了,写一个nb的,如果现在没有这个能力,那么我们就来好好学学别人写好的框架把,首先第一个就是咱们的django框架了,其实就是将这些功能封装起来,并且容错能力强,抗压能力强,总之一个字:吊。# while 1:from_b_msg = conn.recv(1024)str_msg = from_b_msg.decode('utf-8')path = str_msg.split('\r\n')[0].split(' ')[1]print('path>>>',path)# 注意:因为开启的线程很快,可能导致你的文件还没有发送过去,其他文件的请求已经来了,导致你文件信息没有被浏览器正确的认识,所以需要将发送请求行和请求头的部分写道前面的每一个函数里面去,并且防止出现浏览器可能不能识别你的html文件的情况,需要在发送html文件的那个函数里面的发送请求行和请求头的部分加上两个请求头content-type:text/html\r\ncharset:utf-8\r\n# conn.send(b'HTTP/1.1 200 ok\r\n\r\n')  不这样写了# conn.send(b'HTTP/1.1 200 ok\r\ncontent-type:text/html\r\ncharset:utf-8\r\n\r\n')  不这样写了print(from_b_msg)#执行这个fun函数并将路径和conn管道都作为参数传给他fun(path,conn)

根据不同路径返回不同页面的web框架

创建两个html文件,写几个标签在里面,名为index.html和home.html,然后根据不同的路径返回不同的页面,页面不创建了,写一下python代码
"""
根据URL中不同的路径返回不同的内容
返回独立的HTML页面
"""import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听# 将返回不同的内容部分封装成函数
def index(url):# 读取index.html页面的内容with open("index.html", "r", encoding="utf8") as f:s = f.read()# 返回字节数据return bytes(s, encoding="utf8")def home(url):with open("home.html", "r", encoding="utf8") as f:s = f.read()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None  # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息conn.send(response)conn.close()

返回动态页面的web框架

页面显示出来了但是都是静态的。页面内容都不会变化,我想要的是动态网站,动态网站的意思是里面有动态变化的数据,而不是页面里面有动态效果。还是写一下python代码
"""
根据URL中不同的路径返回不同的内容
返回HTML页面
让网页动态起来
"""import socket
import timesk = socket.socket()
sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
sk.listen()  # 监听# 将返回不同的内容部分封装成函数
def index(url):with open("index.html", "r", encoding="utf8") as f:s = f.read()now = str(time.time())s = s.replace("@@oo@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号return bytes(s, encoding="utf8")def home(url):with open("home.html", "r", encoding="utf8") as f:s = f.read()return bytes(s, encoding="utf8")# 定义一个url和实际要执行的函数的对应关系
list1 = [("/index/", index),("/home/", home),
]while 1:# 等待连接conn, add = sk.accept()data = conn.recv(8096)  # 接收客户端发来的消息# 从data中取到路径data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串# 按\r\n分割data1 = data.split("\r\n")[0]url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行# 根据不同的路径返回不同内容func = None  # 定义一个保存将要执行的函数名的变量for i in list1:if i[0] == url:func = i[1]breakif func:response = func(url)else:response = b"404 not found!"# 返回具体的响应消息conn.send(response)conn.close()
别人写好的模块搞得web框架,这个模块是wsgiref:

wsgiref模块版web框架

wsgiref怎么使用:
from wsgiref.simple_server import make_server
# wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便)
#函数名字随便起
def application(environ, start_response):''':param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多你想要拿到的信息:param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数:return:'''start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')])print(environ)print(environ['PATH_INFO'])  #输入地址127.0.0.1:8000,这个打印的是'/',输入的是127.0.0.1:8000/index,打印结果是'/index'return [b'<h1>Hello, web!</h1>']#和咱们学的socketserver那个模块很像啊
httpd = make_server('127.0.0.1', 8080, application)print('Serving HTTP on port 8080...')
# 开始监听HTTP请求:
httpd.serve_forever()

模版渲染jinja2

下载方式
pip install jinja2
需要一个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>
使用jinja2渲染的html2文件
from wsgiref.simple_server import make_server
from jinja2 import Templatedef index():with open("index2.html", "r",encoding='utf-8') as f:data = f.read()template = Template(data)  # 生成模板文件ret = template.render({"name": "于谦", "hobby_list": ["烫头", "泡吧"]})  # 把数据填充到模板里面return [bytes(ret, encoding="utf8"), ]# 定义一个url和函数的对应关系
URL_LIST = [("/index/", index),
]def run_server(environ, start_response):start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息url = environ['PATH_INFO']  # 取到用户输入的urlfunc = None  # 将要执行的函数for i in URL_LIST:if i[0] == url:func = i[1]  # 去之前定义好的url列表里找url应该执行的函数breakif func:  # 如果能找到要执行的函数return func()  # 返回函数的执行结果else:return [bytes("404没有该页面", encoding="utf8"), ]if __name__ == '__main__':httpd = make_server('', 8000, run_server)print("Serving HTTP on port 8000...")httpd.serve_forever()
从数据库查询数据填充页面
使用pymysql连接数据库
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("select name, age, department_id from userinfo")
user_list = cursor.fetchall()
cursor.close()
conn.close()
测试user表
CREATE TABLE user(id int auto_increment PRIMARY KEY,name CHAR(10) NOT NULL,hobby CHAR(20) NOT NULL
)engine=innodb DEFAULT charset=UTF8;

MVC和MTV框架

  M:model.py 就是和数据库打交道用的,创建表等操作
  V:View 视图(视图函数,html文件)
  C:controller 控制器(其实就是我百度云代码里面那个urls文件里面的内容,url(路径)分发与视图函数的逻辑处理)
  Django叫做MTV框架
    M:model.py 就是和数据库打交道用的,创建表等操作(和上面一样)
    T:templates 存放HTML文件的
    V:View 视图函数(逻辑处理)

转载于:https://www.cnblogs.com/shuai-jie/p/11227004.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363517.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot 系列(十三)使用邮件服务

在我们这个时代&#xff0c;邮件服务不管是对于工作上的交流&#xff0c;还是平时的各种邮件通知&#xff0c;都是一个十分重要的存在。Java 从很早时候就可以通过 Java mail 支持邮件服务。Spring 更是对 Java mail 进行了进一步的封装&#xff0c;抽象出了 JavaMailSender. 后…

服务器能否只做c盘系统,我的云服务器只有一个c盘

我的云服务器只有一个c盘 内容精选换一换检查Pkey是否一致。查看弹性云服务器内部分配到的Pkey&#xff1a;cat /sys/class/infiniband/mlx5_0/ports/1/pkeys/* | grep -v "0x0000"检查Pkey是否一致如果环境中查出来的Pkey只有一个&#xff0c;请联系技术支持人员。如…

单例模式(C++实现)

RAII运用 只能在栈上创建对象 只能在堆上创建的对象 单例模式 设计模式 懒汉模式 解决线程安全 优化 饿汉模式 饿汉和懒汉的区别

Flume:使用Apache Flume收集客户产品搜索点击数据

这篇文章涵盖了使用Apache flume收集客户产品搜索点击并使用hadoop和elasticsearch接收器存储信息。 数据可能包含不同的产品搜索事件&#xff0c;例如基于不同方面的过滤&#xff0c;排序信息&#xff0c;分页信息&#xff0c;以及进一步查看的产品以及某些被客户标记为喜欢的…

vue-cli使用swiper4在ie以及safari报错

vue-cli项目中&#xff0c;通过npm run swiper --save-dev安装的是swiper4版本的插件&#xff0c;这样安装以后在谷歌火狐等浏览器都可以正常运行&#xff0c;但是在safari浏览器&#xff08;可能是版本太低&#xff09;还有ie&#xff08;9,10,11&#xff09;打开会报错&#…

电脑内部,小贴士:电脑内部连接标准

小贴士&#xff1a;电脑内部连接标准在介绍电脑内部连接标准之前&#xff0c;首先应该了解一下电脑内部接线的种类&#xff0c;以便分类处置。电脑内部尽管五颜六色的导线&#xff0c;其中导线的种类可以分为3 类&#xff0c;即电源线、信号线和控制线&#xff0c;而控制线又常…

太快了,太变态了:什么会影响Java中的方法调用性能?

那么这是怎么回事&#xff1f; 让我们从一个简短的故事开始。 几周前&#xff0c;我提议对Java核心libs邮件列表进行更改 &#xff0c;以覆盖当前final一些方法。 这刺激了一些讨论主题-其中之一是其中一个性能回归通过采取这是一个方法被引入的程度final免遭停止它final 。 我…

1、dubbo的概念

Dubbo是什么&#xff1f; Dubbo是阿里巴巴SOA服务化治理方案的核心框架&#xff0c;每天为2,000个服务提供3,000,000,000次访问量支持&#xff0c;并被广泛应用于阿里巴巴集团的各成员站点。Dubbo[]是一个分布式服务框架&#xff0c;致力于提供高性能和透明化的RPC远程服务调用…

轻云服务器的性能,腾讯云轻量应用服务器性能评测(以香港地域为例)

腾讯云轻量应用服务器香港节点24元/月&#xff0c;价格很不错&#xff0c;ForeignServer来说说腾讯云轻量服务器香港地域性能评测&#xff0c;包括腾讯云轻量应用服务器CPU型号配置、网络延迟速度测试&#xff1a;腾讯云香港轻量应用服务器性能评测腾讯云轻量应用服务器地域可选…

vue2.5.2版本 :MAC设置应用在127.0.0.1:80端口访问; 并将127.0.0.1指向www.yours.com ;问题“ Invalid Host header”

0.设置自己的host文件&#xff0c;将127.0.0.1指向自己想要访问的域名 127.0.0.1 www.yours.com 1.MAC设置应用在127.0.0.1&#xff1a;80端口访问&#xff1a; config/index.js目录下修改host和port 然后sudo运行npm run dev:(mac的80端口是被自身分享应用占用的&#xff0c…

Google Android 平台正式开源

Google 推出移动设备软件平台 Android 之时&#xff0c;曾向开发者开放 SDK 包&#xff0c;并许诺将在开源许可模式下开放其全部代码&#xff0c;今天&#xff0c;Google 与其合作伙伴&#xff0c;在 Open Handset Alliance 兑现了其承诺&#xff0c;用户现在可以正式下载 Andr…

JSP彩色验证码

产生验证码图片的文件-----image.jsp <% page contentType"image/jpeg" import"java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %><%!Color getRandColor(int fc,int bc){//给定范围获得随机颜色 Random random new Random()…

自定义Windows右击菜单调用Winform程序

U9_Git中ignore文件处理 背景 U9代码中有许多自动生成的文件&#xff0c;不需要上传Git必须BE Entity中的.target文件 .bak 文件 Enum.cs结尾的文件&#xff0c;还有许多 extand文件。 这些文件都不需要上传Git。 但是这些文件太多了&#xff0c;不可能手动加入到ignore文件中。…

Gradle Introduction

目录 Compileing development ProcessOld compile MothedModern compile MothedWhat is GradleGradle EffectWhat is GroovyGroovy syntax relesStructure ScriptPeojectAttributeTaskExample #1applyExample #1Example #2Dependency ManagementExample #1Example #2Multiple P…

u8系统怎么连接服务器,用友U8 怎么连接远程服务器

用友U8 怎么连接远程服务器 内容精选换一换配置应用系统的跨云热备容灾方案如图1所示。在如图1所示的方案中&#xff0c;用户的生产数据中心的应用系统使用MySQL作为数据库&#xff0c;应用系统与MySQL均热备容灾到华为云上。用户的生产数据中心与华为云之间使用专线进行网络连…

[导入]商业智能2.0?(BI 2.0 from Timo Elliott)

译者注: 关于BI2.0的说法很多&#xff0c;不尽一致&#xff0c;目的只是想多了解一些&#xff1b;译文并不代表译者认可原文观点&#xff0c;只是顺便译了以方便不喜欢E文的朋友。本文是一篇充满探讨及疑问的文章&#xff0c;来自Timo Elliott(Business Objects历史上的第8号员…

angularjs封装bootstrap官网的时间插件datetimepicker

背景:angular与jquery类库的协作 第三方类库中&#xff0c;不得不提的是大名鼎鼎的jquery,现在基本上已经是国内web开发的必修工具了。它灵活的dom操作&#xff0c;让很多web开发人员欲罢不能。再加上已经很成熟的jquery UI 库和大量jquery 插件&#xff0c;几乎是一个取之不尽…

Java中的得墨meter耳定律–最少知识原理–实际示例

得墨meter耳定律&#xff08;也称为最少知识定律&#xff09;是一种编码原理&#xff0c;它表示模块不应该知道其操作的对象的内部细节。 如果代码依赖于特定对象的内部细节&#xff0c;则很有可能一旦该对象的内部发生更改&#xff0c;它就会被破坏。 由于封装是关于隐藏对象的…

课后作业1

自我介绍 我叫张阔&#xff0c;我的爱好是旅行&#xff0c;游览世界的美好风光&#xff1b; 我的码云个人主页是&#xff1a;https://gitee.com/ZkTt0428&#xff1b; 我的第一个项目地址是&#xff1a;https://gitee.com/ZkTt0428/Frist&#xff1b; 目前代码量有10000行了&am…

针对新手的Java EE7和Maven项目-第4部分-定义Ear模块

从前面的部分恢复 第1部分 第2部分 第3部分 我们正在恢复第四部分&#xff0c;目前我们的简单项目有 Web Maven模块&#xff08;战争&#xff09; 一个ejb模块&#xff08;ejb&#xff09;&#xff0c;其中包含我们的无状态会话bean&#xff08;EJB 3.1&#xff09; 第二…