Python入门自学进阶-Web框架——1、认识WEB服务器及框架

框架,即framework,是解决一个开放性问题而设计的具有一定约束性的支撑结构。

DRP原则:Don't RePeat yourself。

web应用的流程:

  • 浏览器发送一个HTTP请求
  • 服务器收到请求,生成一个HTML文档
  • 服务器把HTML文档作为HTTP响应的Body发送给浏览器
  • 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示

对于所有的Web应用,本质上其实就是一个socket服务端,用户浏览器其实就是一个socket客户端。

python实现上述过程,也就是模拟一个web服务器跟浏览器的交互过程:

import socket

def handle_request(client):
    buf = client.recv(1024)
    print(buf.decode("utf8"))
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("

Hello,people

".encode("utf8")) def main(): sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(("localhost",8001)) sock.listen(5) while True: connection,address = sock.accept() handle_request(connection) connection.close() if __name__ == "__main__": main()

Python入门自学进阶-Web框架——1、认识WEB服务器及框架_第1张图片

python程序就是最简单的web服务器,绑定localhost和8001端口,等待客户端的访问,有客户端访问,就将发送HTTP响应头和响应体,这是符合HTTP协议的文本,浏览器取出响应体,在浏览器上呈现。

浏览器发送给服务器的内容:

GET /test/ HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrftoken=a9rnZVOsgjI4HZjgDYeJnIsxs1DUVCoYrfmmiLWEPN7Mu0C8oDjyPCTrtLFtQRrU 

对于这个程序,浏览器端只要主机地址和端口写准确,后面写什么都能访问到,端口后面的部分,这里是/test/,就可以作为不同响应内容的区分标志。

如果将:client.send("

Hello,people

".encode("utf8"))这一句,即要响应的内容写在一个文件中,并把这个文件命名为index.html,如下:

import socket

def handle_request(client):
    buf = client.recv(1024)
    print(buf.decode("utf8"))
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    # client.send("

Hello,people

".encode("utf8")) with open ("index.html","rb") as f: data = f.read() client.send(data) def main(): sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind(("localhost",8001)) sock.listen(5) while True: connection,address = sock.accept() handle_request(connection) connection.close() if __name__ == "__main__": main()

index.html如下:




    
    Title


Hello,people in file

浏览器访问:

Python入门自学进阶-Web框架——1、认识WEB服务器及框架_第2张图片

服务器端接收到的浏览器发送的信息:

GET /index.html HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0 
。。。。。

这就成了一个最简单的web服务器了。可以根据浏览器端发来的第一行的GET或POST后的内容来区分不同的网页返回给浏览器就行了。

上述的过程,进行归纳抽取,可以形成如下几个部分:

1、是服务器部分,就是上面的sock,需要绑定地址跟端口,需要等待,这需要高的性能和高并发性,可以抽取成框架的一部分。
2、接收到的客户端信息即HTTP请求,需要能够解析,即解析浏览器发送的信息,如想获取host信息,想获取资源位置信息等。
3、向客户端发送响应头和响应体,需要符合HTTP协议的内容。

以上都可以抽取成框架的一部分,最后形成整个web服务器。

python有这样的一个接口就是WSGI:Web Server Gateway Interface,实际就是一个最简单的web框架:

from wsgiref.simple_server import  make_server

def application(environ,start_response):
    # 通过environ封装成一个所有请求信息及本机信息的对象,是字典对象
    # start_response可以方便的设置响应头
    start_response('200 OK',[('Content-Type','text/html')])
    return [b'

hello,web!

'] # 封装socket对象以及准备过程(socket,bind,listen) httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()

这里make_server就完成了上面的sock的创建、绑定、监听过程,application用来格式化完成响应头的形成和响应体的反馈。

根据不同的请求资源,返回不同的页面内容:

from wsgiref.simple_server import  make_server

def application(environ,start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    if environ["PATH_INFO"] == "/":
        return [b'

hello,index!

'] elif environ["PATH_INFO"] == "/book": return [b'

hello,book!

'] else: return [b'

404!

'] httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()

实际中一个网站会有很多不同页面,所以如果按照上面的写法,会有很长的if。。。else语句,而且,返回给客户端的内容也不会这么简单,所以程序解耦和规范化,如下:

第一步,使返回内容解耦,以一个单独函数进行返回内容的处理:

from wsgiref.simple_server import  make_server

def f1(req):
    print(req['PATH_INFO'],"根据f1的页面业务进行处理,形成返回内容")
    return [b'

hello,index!

'] def f2(req): print(req['PATH_INFO'], "根据f2的页面业务进行处理,形成返回内容") return [b'

hello,book!

'] def application(environ,start_response): start_response('200 OK', [('Content-Type', 'text/html')]) if environ["PATH_INFO"] == "/": return f1(environ) elif environ["PATH_INFO"] == "/book": return f2(environ) else: return [b'

404!

'] httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()

第二步,处理if。。。else问题:

from wsgiref.simple_server import  make_server

def f1(req):
    print(req['PATH_INFO'],"根据f1的页面业务进行处理,形成返回内容")
    return [b'

hello,index!

'] def f2(req): print(req['PATH_INFO'], "根据f2的页面业务进行处理,形成返回内容") return [b'

hello,book!

'] def f3(req): print(req['PATH_INFO'], "根据f2的页面业务进行处理,形成返回内容") return [b'

hello,web!

'] def f4(req): print(req['PATH_INFO'], "根据f2的页面业务进行处理,形成返回内容") return [b'

hello,popo!

'] def routers(): #形成访问路径与最终返回内容的映射元组 urlpatterns = ( ("/",f1), ("/popo",f2), ("/web",f3), ("/book",f4) ) return urlpatterns def application(environ,start_response): start_response('200 OK', [('Content-Type', 'text/html')]) #下面用一个循环替代所有的if。。。else判断,增加新页面,只需在routers中增加相应元组和对应的处理函数即可 path = environ["PATH_INFO"] urlpatterns = routers() func = None for item in urlpatterns: if item[0] == path: func = item[1] break if func: return func(environ) else: return [b'

404!

'] # if environ["PATH_INFO"] == "/": # return f1(environ) # elif environ["PATH_INFO"] == "/book": # return f2(environ) # else: # return [b'

404!

'] httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()

第三步,关于解耦出的函数,进行文件内容替换,实际就是模板文件内容替换:这里实际上定义了一种新模板语言,用!!中间加变量进行替换

from wsgiref.simple_server import  make_server
import time

def f1(req):
    cur_time = time.ctime(time.time())
    with open("index.html","rb") as f:
        data = f.read()
    return_data = data.decode("utf8").replace("!cur_time!",str(cur_time))
    return [return_data.encode("utf8")]
def f2(req):
    return [b'

hello,book!

'] def f3(req): return [b'

hello,web!

'] def f4(req): return [b'

hello,popo!

'] def routers(): #形成访问路径与最终返回内容的映射元组 urlpatterns = ( ("/",f1), ("/popo",f2), ("/web",f3), ("/book",f4), ) return urlpatterns def application(environ,start_response): start_response('200 OK', [('Content-Type', 'text/html')]) #下面用一个循环替代所有的if。。。else判断,增加新页面,只需在routers中增加相应元组和对应的处理函数即可 path = environ["PATH_INFO"] print(path) urlpatterns = routers() func = None for item in urlpatterns: if item[0] == path: func = item[1] print(item[1]) break if func: return func(environ) else: return [b'

404!

'] httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()

f1中的替换动作,可以解耦出来,形成单独的模板渲染替换模块。

将上述文件进行彻底解耦,形成各自文件,并形成特定文件目录结构:

Python入门自学进阶-Web框架——1、认识WEB服务器及框架_第3张图片

 server.py文件是主服务器文件,负责整个服务器的配置与启动;urls.py用于资源路径与对应函数的对应关系配置,是起到路径分配作用,以后增加新的资源路径,在这个文件中增加即可;controller.py负责保存各个资源路径对应的处理函数,叫做控制器文件,控制不同资源路径的逻辑处理业务;model.py是与数据库交互的模块,未来的网页数据一般是来自数据库的;view目录用于保存各个资源路径所对应的页面模板。这样拆分下来,逻辑就非常清晰了。

# server.py  服务器主模块
from wsgiref.simple_server import  make_server
from week14.website.urls import routers

def application(environ,start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    #下面用一个循环替代所有的if。。。else判断,增加新页面,只需在routers中增加相应元组和对应的处理函数即可
#===================================================
    path = environ["PATH_INFO"]
    urlpatterns = routers()
    func = None
    for item in urlpatterns:
        if item[0] == path:
            func = item[1]
            print(item[1])
            break
    if func:
        return func(environ)
    else:
        return [b'

404!

'] #==========这一部分实际就是控制器部分,与资源路径分配结合,控制处理的转向==== httpd = make_server('',8090,application) print("Server HTTP on port 8090...") # 开始监听HTTP请求 httpd.serve_forever()
# urls.py 资源路径分配模块, 专门负责资源路径与处理函数的对应关系
import week14.website.controller
from week14.website.controller import *


def routers():  #形成访问路径与最终返回内容的映射元组
    urlpatterns = (
        ("/",f1),
        ("/popo",f2),
        ("/web",f3),
        ("/book",f4),
    )
    return urlpatterns
#controller.py控制器模块,专门用于存放各个资源路径对应的处理函数,起到控制器的作用

import time

def f1(req):
    cur_time = time.ctime(time.time())
    with open("view/index.html","rb") as f:
        data = f.read()
    return_data = data.decode("utf8").replace("!cur_time!",str(cur_time))
    return [return_data.encode("utf8")]
def f2(req):
    return [b'

hello,book!

'] def f3(req): return [b'

hello,web!

'] def f4(req): return [b'

hello,popo!

']
# model.py,数据库模块,实现与数据库交互的功能

class Db:
    pass

MVC模式和MTV模式:

MVC模式:就是把web应用分为模型(M)、控制器(C)、视图(V)三层,它们之间以一种插件似得,松耦合的方式连接在一起。模型负责业务对象与数据库对象映射(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入,调用模型和视图完成用户的请求。

Python入门自学进阶-Web框架——1、认识WEB服务器及框架_第4张图片

 MTV模型与MVC模型没有大的差别,只是定义有些许不同:
Model(模型):负责业务对象与数据库的对象(ORM)
Template(模板):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
RUL分发器,将一个个的页面请求分发给不同的VIEW处理,VIEW再调用相应的Model和Template

Python提供的Web框架叫做Django,使用的就是MTV模型,根据上面的定义,实际上是把controller叫做了View层,view目录叫做了模板Template层。

Python入门自学进阶-Web框架——1、认识WEB服务器及框架_第5张图片

你可能感兴趣的:(Python入门,python,开发语言,django)