本篇主要内容
本篇主要包括:http的基本结构、http报文常用项的解释以及用python搭建一个最简易的web后台程序。希望通过上一篇及未来的下一篇文章,可以对web网站的运行流程做大致的讲述。
前篇回顾
在上一篇中,我们提到,如果想要通过TCP/IP协议提供的通道,获取到web服务器的HTML
页面,那么我们需要发送某些特定的信息才可以,而不是随意发送信息都可以获取到想要的页面。
![](https://img.haomeiwen.com/i10420503/7762915f2eedf01b.png)
我们所遵循的这个
HTTP协议
(HyperText Transfer Protocol),译作超文本传输协议。被设计用来传输超文本文档,即HTML(Hypertext Markup Language)文档。我们把这些在实际通讯过程中发送的一、HTTP的基本结构
在我们前述的文章中,已经多次提到:http协议中,涉及到两个角色,分别是客户端(client)和服务端(server)。
客户端,用于向服务端发送请求。服务端,响应请求并进行适当的数据返回。
因为分成了两个角色,所以HTTP协议又分为了两个方向: 请求(request)、和响应(response)。客户端发起请求,服务端做出响应。但无论请求和响应,均把一次传输需要传送的内容,分成了两大部分:头(head),和体(body)。
![](https://img.haomeiwen.com/i10420503/dc2c723179218647.png)
以下,分别是请求报文和响应报文的示例:
-
请求报文实例
请求报文
请求返回页面
-
响应报文实例(因为上面网页的返回内容过于复杂,下面的响应报文并不与上面的请求返回页面相对应。)
响应报文
响应报文渲染的页面
通过上述实例,我们可以发现:
- http的请求报文和响应报文其实非常相近,报文格式相同,具体数据项有所差别
- http报文中,报文头和报文体之间,是通过一个空行进行分割的;空格以上,是head,以下是body
- 无论是请求头,还是响应头,报文头的首行和其他行的格式,是完全不一样的,其他行都是以
参数名: 参数值
这种形式组织的数据,而首行的格式则是参数1 参数2 参数3
的格式
报文比对
二、HTTP报文常用项的解释
2.1. 请求头的第一行
![](https://img.haomeiwen.com/i10420503/66d3c594a8bf0f9d.png)
请求头的第一行,从左到右共三个参数:请求方法
、请求URI(请求目标)
、http协议版本
-
请求方法
决定了你以怎样的方式去传递参数(或数据),也决定了服务器应用、后台程序,以什么样的方式去对你进行响应。方法有很多,最最常用的两个是GET
和POST
。方法 一般用法 参数(数据)传递方式 GET 一般用于向server请求资源,如页面、图片等 只能在请求URI后面添加参数 POST 一般用于向server提交数据(或者理解为进行数据交换),比如上传文件、提交需要保存的数据、登录等 可以在请求URI后面添加参数,也可以在请求体中添加数据 -
请求URI(请求目标)
是告诉服务器你想要访问的目标是谁,后面可以以某些方式携带参数,但携带参数的长度有限制,这个不同的浏览器、web服务器应用有不同的限制。
2.2. 响应头的第一行
![](https://img.haomeiwen.com/i10420503/ef7358d8598bc652.png)
每一个http请求,都会有一个响应。http响应头的第一行,也是一共有三个参数:协议版本
、状态码
、状态信息
协议版本不必多说;状态码和状态信息其实是成组对应的,是一个意思,只不过状态码是数字,信息是文字。需要特别指出的是,状态码是http协议级别的信息,不是业务级别的
最最常见的如下表
序号 | 状态码 | 状态信息 | 解释 |
---|---|---|---|
1 | 200 | OK | 表示在http协议级别,请求成功。但具体业务级别并不一定,比如用户登录,整个请求都对,只是密码填错了,那么这里依然是200
|
2 | 404 | Not Found | 你所访问的资源、请求的链接,不存在 |
3 | 500 | Internal Server Error | 服务器内部错误。是我们的程序或者web服务器应用报错了。 |
2.3. 请求头其他行的最常用项
除了第一行外,请求头的其他行的顺序可以修改。有很多网站会对请求头中的项目做出要求,没有某些项可能会导致请求失败,请求头里的项目并不一定完全是规范化的,也有可能出现自定义内容。
这里只解释一项,作为了解,其他参数后续用到时再进行解释。
-
Content-Length
,后面是一个数字,表示body
中数据的长度。
三、 用python搭建一个简易的后台应用
因为要尽可能明白web的运行原理,但又要考虑到降低复杂度,所以我们选定了使用python的flask
包进行后台程序构建。flask
既对http
的复杂部分做了实现和封装,让用户更便于使用;又没有进行更多的模式设计,让我们能够比较直接的感受到web的运行原理。
首先需要安装flask
包:
pip install flask
![](https://img.haomeiwen.com/i10420503/d261bfe33c07c90e.png)
3.1. 具体的代码实现
-
创建一个python文件,后缀名是
.py
。当然,就算后缀不是.py
,只要内容符合python规范,就可以运行。 -
在文档的开头,我们需要引入
flask
包,并且完成对Flask
的初始化from flask import Flask,request # 初始化Flask对象 app=Flask(__name__)
-
每一个给前台使用的链接,对应的都是一个python方法,比如下面这个方法,就是在为前台的
http://127.0.0.1:8120/data/a/b
提供服务。
这段代码的意思是,你只能使用HTTP请求
的GET
方法请求http://127.0.0.1:8120/data/a/b
链接,并且需要在head
中传入name
和age
两个参数。传入这个参数后,程序会对请求进行响应,最终的响应数据是hello <name>(<age>)
链接请求效果
# 绑定方法对应的链接地址及规定的http method @app.route('/data/a/b',methods=['get']) # 声明一个函数,函数名自定义,符合python的要求即可 def test_get_2(): # 在request的head中获取 name 参数 nm=request.args.get("name") # 在request的head中获取 age 参数 ag=request.args.get("age") # 按照约定的格式进行信息的拼接及返回 return "hello "+nm+"("+ag+")"
-
模拟登录过程。涉及到
HTTP POST
,以及数据的本地存储。在真正的web应用中,肯定只是向上面那样,一个请求进来,简单一个合成一下参数就进行响应。我们会遇到大量的数据交互。这些数据是要存储在web服务器设备上的。存储数据,其实也需要很多不同的软件提供支持,一般叫做
数据库
。但目前我们以文件,来代替数据库,实现最简单的登录验证流程。我们首先需要一个文件(我的叫做
user.dat
),来存储用户名和密码。里面的内容如下图:
user.dat
之后,使用如下代码
# 提供登录的URI是 /data/login,只允许使用 HTTP POST方法 @app.route('/data/login',methods=['post']) def my_login(): # 获取request body里面的参数 username,并赋值给变量uname,是用户输入的用户名 uname=request.form.get("username") # 获取request body里面的参数 password,并赋值给变量psword,是用户输入的密码 psword=request.form.get("password") # 打开与python文件同目录下的 user.dat文件,分行读取里面的内容 with open("./user.dat") as f: txt=f.readlines() # 取出第一行数据,作为真正的用户名,去掉结尾的换行符 uname_saved=txt[0].replace("\n","") # 取出第二行数据,作为真正的密码,同样去掉结尾的换行符 psword_saved=txt[1].replace("\n","") # 如果用户输入的用户名正确 并且 密码也正确,则返回 success if uname==uname_saved and psword==psword_saved: return "success" # 有任何不相等的,则返回 failed else: return "failed"
最后,我们在tcp调试助手中,输入如下内容进行尝试
POST /data/login HTTP/1.1 Host: 127.0.0.1:8120 Content-Type: application/x-www-form-urlencoded Content-Length: 31 username=admin&password=a123456
NetAssist发送post请求测试
网友评论