11月24日学习内容整理:Web框架,本质及WSGI,HTTP协议

一、Web框架

1.概念:

CS架,也就是Client/Server模式。每个用户的电脑上安装一个Client,就像QQ这种终端软件

BS架构(Browser/Server模式)越来越流行,也就是用户只需要一个浏览器就足够了

我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。
这样我们就可以自己实现Web框架了

2、HTTP协议

(1)应用背景:

用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定?
你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?
所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

这个规则就是HTTP协议,以后你发送请求信息也好,回复响应信息也罢,都要按照这个规则来。

HTTP是短连接,无状态,不会保存客户端的信息,只是单纯的一发一收

(2)HTTP组成

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。
HTTP响应的Header中有一个Content-Type表明响应的内容格式。如text/html表示HTML网页。

(3)请求和响应

请求::浏览器——>服务端

响应::服务端——>浏览器

》》》HTTP GET请求格式

GET /path HTTP/1.1
header1:v1\r\n
header2:v2\r\n

》》》HTTP POST请求格式

POST /path HTTP/1.1
header1:v1\r\n
header2:v2\r\n
\r\n\r\n
Body...

》》》HTTP响应格式

200 OK
Header1:v1\r\n
Header2:v2\r\n
\r\n\r\n
Body...

总结:

》》》\r\n是header里的分界线同时也是body里的分界线

》》》\r\n\r\n是header和body的分界线,可以依据这个分割来分别得到header和body

》》》/path  指的是路径(就是 127.0.0.1地址:8080服务端端口号/index/,这个/index/就是路径,),可以通过空格分割得到路径,从而再进行进一步的处理来给客户端返回指定的数据 

》》》200是标志位

 

 二、web框架本质和WSGI

对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。

 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框架

1、最最基础简单的Web框架

import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    print(data)
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    conn.send(bytes("<h1>hello...你好啊~</h1>", encoding="utf-8"))  # 响应体
    conn.close()

 

2、不同的URL,返回不同的内容

"""
不同的URL,返回不同的内容
"""
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    # 类型转换 字节类型-->字符串
    data_str = str(data, encoding="utf-8")
    # 取到请求头
    header = data_str.split("\r\n\r\n")[0]
    # 再取到 “GET / HTTP/1.1”
    tmp = header.split("\r\n")[0]
    # 再按照空格分割,得到列表,取索引值是1的
    url = tmp.split(" ")[1]
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    # 根据请求URL的不同,我返回不同的内容
    if url == "/index/":
        response = "这是主页。。。"
    else:
        response = "404"
    conn.send(bytes(response, encoding="utf-8"))  # 响应体
    conn.close()

 

3、通过循环和函数的方式实现不同的URL返回不同的内容

"""
不同的URL,返回不同的内容
"""
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

def index():
    return "这是主页"

def info():
    return "这是个人信息页"


url_func_map = [
    ("/index/", index),
    ("/info/", info)
]


while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    # 类型转换 字节类型-->字符串
    data_str = str(data, encoding="utf-8")
    # 取到请求头
    header = data_str.split("\r\n\r\n")[0]
    # 再取到 “GET / HTTP/1.1”
    tmp = header.split("\r\n")[0]
    # 再按照空格分割,得到列表,取索引值是1的
    url = tmp.split(" ")[1]
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    # 根据请求URL的不同,我返回不同的内容
    func_name = None  # 定义一个存放将要执行函数的变量
    # for循环url_func_map
    for i in url_func_map:
        if i[0]  == url:
            func_name = i[1]
            break
    if func_name:
        response = func_name()
    else:
        response = "404"
    conn.send(bytes(response, encoding="utf-8"))  # 响应体
    conn.close()

 

4、根据不同的URL返回不同的html文件

"""
不同的URL,返回不同的内容
返回的内容要是我写好的html文件
"""
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

def login():
    with open("login.html", encoding="utf-8") as f:
        data = f.read()
    return data

def index():
    with open("index.html", encoding="utf-8") as f:
        data = f.read()
    return data

def info():
    return "这是个人信息页"


url_func_map = [
    ("/login/", login),
    ("/index/", index),
    ("/info/", info)
]


while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    # 类型转换 字节类型-->字符串
    data_str = str(data, encoding="utf-8")
    # 取到请求头
    header = data_str.split("\r\n\r\n")[0]
    # 再取到 “GET / HTTP/1.1”
    tmp = header.split("\r\n")[0]
    # 再按照空格分割,得到列表,取索引值是1的
    url = tmp.split(" ")[1]
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    # 根据请求URL的不同,我返回不同的内容
    func_name = None  # 定义一个存放将要执行函数的变量
    # for循环url_func_map
    for i in url_func_map:
        if i[0]  == url:
            func_name = i[1]
            break
    if func_name:
        response = func_name()
    else:
        response = "404"
    conn.send(bytes(response, encoding="utf-8"))  # 响应体
    conn.close()

 

5、4的基础上,html的内容要动起来

"""
不同的URL,返回不同的内容
返回的内容要是我写好的html文件
html里面的内容要动起来
"""
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

def login():
    with open("login.html", encoding="utf-8") as f:
        data = f.read()
    import time
    time_s = str(time.time())
    data_new = data.replace("@@xx@@", time_s)
    return data_new

def index():
    with open("index.html", encoding="utf-8") as f:
        data = f.read()
    return data

def info():
    return "这是个人信息页"


url_func_map = [
    ("/login/", login),
    ("/index/", index),
    ("/info/", info)
]


while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    # 类型转换 字节类型-->字符串
    data_str = str(data, encoding="utf-8")
    # 取到请求头
    header = data_str.split("\r\n\r\n")[0]
    # 再取到 “GET / HTTP/1.1”
    tmp = header.split("\r\n")[0]
    # 再按照空格分割,得到列表,取索引值是1的
    url = tmp.split(" ")[1]
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    # 根据请求URL的不同,我返回不同的内容
    func_name = None  # 定义一个存放将要执行函数的变量
    # for循环url_func_map
    for i in url_func_map:
        if i[0]  == url:
            func_name = i[1]
            break
    if func_name:
        response = func_name()
    else:
        response = "404"
    conn.send(bytes(response, encoding="utf-8"))  # 响应体
    conn.close()

 

6、5的基础上,数据从数据库中提取

"""
不同的URL,返回不同的内容
返回的内容要是我写好的html文件
html里面的内容要动起来
数据要从数据库中查找
"""
import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 8080))
sk.listen(5)

def login():
    with open("login.html", encoding="utf-8") as f:
        data = f.read()
    import time
    time_s = str(time.time())
    data_new = data.replace("@@xx@@", time_s)
    return data_new

def index():
    with open("index.html", encoding="utf-8") as f:
        data = f.read()
    # 链接数据库,找数据
    import pymysql
    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="", db="day48", charset="utf-8")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select id, name, balance from user")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()
    """
    <tr>
        <td>id</td>
        <td>name</td>
        <td>balance</td>
    </tr>
    """
    ret = ""
    for i in user_list:
        ret +=  """
            <tr>
                <td>{0}</td>
                <td>{1}</td>
                <td>{2}</td>
            </tr>
        """.format(i["id"], i["name"], i["balance"])
    data_new = data.replace("@@xx@@", ret)
    return data_new


def info():
    return "这是个人信息页"


url_func_map = [
    ("/login/", login),
    ("/index/", index),
    ("/info/", info)
]


while True:
    conn, addr = sk.accept()  # 夯在此地,等待链接
    data = conn.recv(8096)
    # 类型转换 字节类型-->字符串
    data_str = str(data, encoding="utf-8")
    # 取到请求头
    header = data_str.split("\r\n\r\n")[0]
    # 再取到 “GET / HTTP/1.1”
    tmp = header.split("\r\n")[0]
    # 再按照空格分割,得到列表,取索引值是1的
    url = tmp.split(" ")[1]
    conn.send(b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")  # 响应头
    # 根据请求URL的不同,我返回不同的内容
    func_name = None  # 定义一个存放将要执行函数的变量
    # for循环url_func_map
    for i in url_func_map:
        if i[0]  == url:
            func_name = i[1]
            break
    if func_name:
        response = func_name()
    else:
        response = "404"
    conn.send(bytes(response, encoding="utf-8"))  # 响应体
    conn.close()

 

posted @ 2017-11-24 14:22  九二零  阅读(133)  评论(0编辑  收藏  举报