HTTP协议|web框架

时间:2022-07-30 13:42:32

1、web应用 

  Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。应用程序有两种模式C/S、B/S。C/S是客户端/服务器端程序,也就是说这类程序一般独立运行。而B/S就是浏览器端/服务器端应用程序,这类应用程序一般借助谷歌,火狐等浏览器来运行。WEB应用程序一般是B/S模式。Web应用程序首先是“应用程序”,和用标准的程序语言,如java,python等编写出来的程序没有什么本质上的不同。在网络编程的意义下,浏览器是一个socket客户端,服务器是一个socket服务端。

web框架

  Web框架(Web framework)是一种开发框架,用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方法。web框架已经实现了很多功能,开发人员使用框架提供的方法并且完成自己的业务逻辑,就能快速开发web应用了。浏览器和服务器的是基于HTTP协议进行通信的。也可以说web框架就是在以上十几行代码基础张扩展出来的,有很多简单方便使用的方法,大大提高了开发的效率。

wsgiref模块

  最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块。

from wsgiref.simple_server import make_ser

遵循http协议

字符串必须按照某种格式发给浏览器

import socket
sock = socket.socket()
sock.bind(('127.0.0.1',8800))
sock.listen(5)

while 1:
    print('server waiting')
    conn,addr = sock.accept()
    data = conn.recv(1024)
    print("data",data)
    conn.send(b"HTTP/1.1 200 OK\r\n\r\nHello luffycity!")
    conn.close()

打印:
server waiting
data b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nUpgrade-Insecure-Requests: 1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting
data b'GET /favicon.ico HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://127.0.0.1:8800/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting

HTTP协议|web框架

 

import socket
sock = socket.socket()
sock.bind(('127.0.0.1',8800))
sock.listen(5)

while 1:
    print('server waiting')
    conn,addr = sock.accept()
    data = conn.recv(1024)
    print("data",data)

    #读取html文件
    with open('index.html','rb')as f:
        data = f.read()
    conn.send((b"HTTP/1.1 200 OK\r\n\r\n%s"%data))
    conn.close()

打印:(get请求)
server waiting
data b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting
data b'GET /favicon.ico HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://127.0.0.1:8800/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Hello Luffycity!</h1>
    <img src="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/w%3D268%3Bg%3D0/sign=16535fed6163f6241c5d3e05bf7f8cc5/fd039245d688d43f63d84526771ed21b0ff43bf5.jpg">
    <a href="http://www.luffycity.com">路飞学城</a>
</body>
</html>

HTTP协议|web框架

post请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="http://127.0.0.1:8800/" method="post">
        用户名<input type="text" name="user">
        密码<input type="password" name="pwd">
        <input type="submit">
    </form>
</body>
</html>
import socket
sock = socket.socket()
sock.bind(('127.0.0.1',8800))
sock.listen(5)

while 1:
    print('server waiting')
    conn,addr = sock.accept()
    data = conn.recv(1024)
    print("data",data)

    #读取html文件
    with open('login.html','rb')as f:
        data = f.read()
    conn.send((b"HTTP/1.1 200 OK\r\n\r\n%s"%data))
    conn.close()

打印:(post请求)
server waiting
data b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nUpgrade-Insecure-Requests: 1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting
data b'GET /favicon.ico HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://127.0.0.1:8800/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting
data b''
server waiting
data b''
server waiting
data b''
server waiting
data b''
server waiting
data b'POST / HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nContent-Length: 20\r\nCache-Control: max-age=0\r\nOrigin: http://127.0.0.1:8800\r\nUpgrade-Insecure-Requests: 1\r\nContent-Type: application/x-www-form-urlencoded\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nReferer: http://127.0.0.1:8800/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\nuser=egon&pwd=abc123'
server waiting
data b'GET /favicon.ico HTTP/1.1\r\nHost: 127.0.0.1:8800\r\nConnection: keep-alive\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36\r\nAccept: image/webp,image/apng,image/*,*/*;q=0.8\r\nReferer: http://127.0.0.1:8800/\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=Mrqe5gm2pfaQy6LqXAJDqcWWU3BfTFrB0LMMhAEv2Pi0STKVn95bR6ODrDPZn34j\r\n\r\n'
server waiting

HTTP协议|web框架

 

2、http协议简介 

HTTP协议|web框架

特性:

http协议是基于TCP/IP协议之上的应用层协议基于请求响应模式:先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应;无状态保持:HTTP是一种不保存状态,即无状态(stateless)协议,HTTP协议 自身不对请求和响应之间的通信状态进行保存,也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。

使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成 如此简单的。可是,随着Web的不断发展,因无状态而导致业务处理变得棘手 的情况增多了。比如,用户登录到一家购物网站,即使他跳转到该站的 其他页面后,也需要能继续保持登录状态。针对这个实例,网站为了能 够掌握是谁送出的请求,需要保存用户的状态。HTTP/1.1虽然是无状态协议,但为了实现期望的保持状态功能, 于是引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管 理状态了。

无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

 

HTTP协议|web框架

HTTP协议|web框架

请求协议与响应协议

http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的请求协议。用于HTTP协议交互的信被为HTTP报文。请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。HTTP报文本身是由多行数据构成的字 文本。 

HTTP协议|web框架

请求协议:请求报文的构成见下

HTTP协议|web框架

get请求没有请求体,会放在url后面;只有post请求才有请求体;

请求方式: get与post请求

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的请求体中.
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
    GET与POST请求在服务端获取请求数据方式不同。

响应协议

 响应格式:

HTTP协议|web框架

响应状态码

HTTP协议|web框架

重定向(地址搬家了,换成另外一个域名了。)

web框架

wsgi接口协议,基于接口实现的wsgiref

 

.ico是浏览器发的一个图标请求;

图标请求

 

from wsgiref.simple_server import make_server

def application(environ, start_response): #请求来了就用application来处理;所有的数据都在environ这个字典里,start_response来给我们处理格式
    start_response('200 OK', [('Content-Type','text/html')]) #状态码、响应头
    print("PATH", environ.get("PATH_INFO"))
    path = environ.get("PATH_INFO")
    if path == "/favicon.ico":
        '''return [b"hello favicon.ico"] #浏览器想得到一个图片你却给了它个字符串'''
        with open("favicon.ico",'rb') as f:
            data = f.read()
        return [data]
    return [b'<h1>Hello,web!</h1>']
httpd = make_server('', 8080, application) #封装的socket
print('Serving HTTP on port 8000.。')
#开始监听HTTP请求:
httpd.serve_forever()

打印:
Serving HTTP on port 8000.。
PATH /kris
127.0.0.1 - - [24/May/2018 17:48:56] "GET /kris HTTP/1.1" 200 19
127.0.0.1 - - [24/May/2018 17:48:56] "GET /favicon.ico HTTP/1.1" 200 25214
PATH /favicon.ico

HTTP协议|web框架

方案一:

from wsgiref.simple_server import make_server

def application(environ, start_response): #请求来了就用application来处理;所有的数据都在environ这个字典里,start_response来给我们处理格式
    start_response('200 OK', [('Content-Type','text/html')]) #状态码、响应头
    print("PATH", environ.get("PATH_INFO"))
    path = environ.get("PATH_INFO")
    if path == "/favicon.ico":
        '''return [b"hello favicon.ico"] #浏览器想得到一个图片你却给了它个字符串'''
        with open("favicon.ico",'rb') as f:
            data = f.read()
        return [data]
    elif path == "/login":
        with open("login.html","rb")as f:
            data = f.read()
        return [data]
    elif path == "/index":
        with open("index.html","rb")as f:
            data = f.read()
        return [data]
    return [b'<h1>Hello,web!</h1>']
httpd = make_server('', 8080, application) #封装的socket
print('Serving HTTP on port 8000.。')
#开始监听HTTP请求:
httpd.serve_forever()
#打印:
Serving HTTP on port 8000.。
PATH /index
127.0.0.1 - - [24/May/2018 18:00:55] "GET /index HTTP/1.1" 200 394
127.0.0.1 - - [24/May/2018 18:07:08] "GET /index/login HTTP/1.1" 200 19
PATH /index/login
PATH /login
127.0.0.1 - - [24/May/2018 18:07:21] "GET /login HTTP/1.1" 200 363

方案2 改善

from wsgiref.simple_server import make_server

def login(): #给它加个参数environ ,给它传请求接收信息,它用不用的到再说
    with open("login.html","rb")as f:
        data = f.read()
    return data
def index(): #environ
    with open("index.html","rb")as f:
        data = f.read()
    return data
def favi(): #environ
    with open("favicon.ico", "rb")as f:
        data = f.read()
    return data #你们返回数据,我把数据返回到列表里

def reg(): #environ
    with open("regs.html", "rb")as f:
        data = f.read()
    return data

def application(environ, start_response): #请求来了就用application来处理;所有的数据都在environ这个字典里,start_response来给我们处理格式
    start_response('200 OK', [('Content-Type','text/html')]) #状态码、响应头
    print("PATH", environ.get("PATH_INFO"))
    #当前请求路径
    path = environ.get("PATH_INFO")

    url_patterns = [
        ("/login", login),
        ("/regs", reg),
        ("/index", index),
        ("/favicon.ico",favi)
    ]

    func = None
    for item in url_patterns:
        if path == item[0]:
            func = item[1]  #跟上边的login匹配成功了
            break
    if func:
        return [func()]  #给它加个参数environ
    else:
        return [b'404!']

httpd = make_server('', 8080, application) #封装的socket
print('Serving HTTP on port 8000.。')
#开始监听HTTP请求:
httpd.serve_forever()

打印:(与浏览器的交互)
Serving HTTP on port 8000.。
PATH /
127.0.0.1 - - [24/May/2018 18:31:58] "GET / HTTP/1.1" 200 4
127.0.0.1 - - [24/May/2018 18:32:08] "GET /login HTTP/1.1" 200 363
PATH /login
PATH /reg
127.0.0.1 - - [24/May/2018 18:32:17] "GET /reg HTTP/1.1" 200 4
127.0.0.1 - - [24/May/2018 18:32:22] "GET /regs HTTP/1.1" 200 157
PATH /regs

继续优化

把html和图标放在templates里边

HTTP协议|web框架

views.py

#把这些函数都放在一个py文件里边
def login(environ):  #必须给它传请求接收信息,用不用得到再说
    with open("templates/login.html","rb")as f:
        data = f.read()
    return data
def index(environ):
    with open("templates/index.html","rb")as f:
        data = f.read()
    return data
def favi(environ):
    with open("templates/favicon.ico", "rb")as f:
        data = f.read()
    return data #你们返回数据,我把数据返回到列表里

def reg(environ):
    with open("templates/regs.html", "rb")as f:
        data = f.read()
    return data

 

urls.py

from views import *
url_patterns = [
        ("/login", login),  #视图函数
        ("/regs", reg),
        ("/index", index),
        ("/favicon.ico",favi)
]

main.py

from wsgiref.simple_server import make_server

def application(environ, start_response): #请求来了就用application来处理;所有的数据都在environ这个字典里,start_response来给我们处理格式
    start_response('200 OK', [('Content-Type','text/html')]) #状态码、响应头
    print("PATH", environ.get("PATH_INFO"))
    #当前请求路径
    path = environ.get("PATH_INFO")

    from urls import url_patterns
    func = None
    for item in url_patterns:
        if path == item[0]:
            func = item[1]  #跟上边的login匹配成功了
            break
    if func:
        return [func(environ)]
    else:
        return [b'404!']

httpd = make_server('', 8080, application) #封装的socket
print('Serving HTTP on port 8000.。')
#开始监听HTTP请求:
httpd.serve_forever()