与HTTP的第一次亲密接触

aside section ._1OhGeD · · 745 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

HTTP协议的学习,我之前避开了最基础最概念的东西,写到现在,我发现若是以前从来没接触过服务端,没了解过抓包,还不知道ABNF的一些核心规则。根本没法继续学下去

网络协议的概念实在太多,不动手实操一下,不仅记不住还难以理解。今天我们就与HTTP协议,进行一次亲密接触~

今天我在这儿就借着Form表单提交发生的HTTP传输,来说下如何搭建Web服务器,以及如何抓包

关于ABNF的语法之后会结合实践,专门写一篇ABNF核心规则是如何描述HTTP的

今天我们就先来说一下Web服务的搭建吧,搭建服务器对应的代码,我已经放到了GitHub仓库上,文章中就仅截取片段代码了。GitHub Repo地址点击跳转,也可以直接clone到你们自己本地

https://github.com/AdolphKevin/http-study-go.git

刚好我们大多数读者也正在学习Golang,我们就用Golang来搭建一个我们自己的服务端,用来与客户端交互,最后我们再用wireshark切身体会一下HTTP协议的传输过程

我在这选择的框架是beego,原因就是搭建Web服务器快,而且文档都是中文文档,有兴趣深入了解框架的可以更方便的学习,最最重要的一点,用go get命令安装时不会被墙

我们就先把环境搭建起来,在这需要安装的东西有

beego
bee
wireshark

如果还没有安装过go的,可以看我之前的文章Vscode搭建go开发环境

beego以及bee的安装

$ go get -u github.com/astaxie/beego
$ go get -u github.com/beego/bee

我在这唯一值得提一点的事情就是bee的环境配置,这点网上虽然有,但是一堆坑。文档也没明说,所以我在这说一下

Mac/Linux下的bee配置

不是把下面的内容全部放到Terminal里面执行的,具体的执行步骤写在注释里了

# 打开配置文件
Vim ~/.bash_profile
## 加入下面两行
export GOPATH=/Users/naonao/go
export PATH=${PATH}:${GOPATH}/bin
## 重启配置文件
source ~/.bash_profile 

不知道GOPATH的路径在哪里,可以执行下go env看看

在这我都说声抱歉,因为在外面出差,Windows下我没电脑搭建,所以没法写具体的操作步骤了,各位网上找找吧。思路就是将GOPATH下的bin文件夹,加入环境变量里

搭建Web服务器

配置好环境变量后,我们可以快速的搭建自己的Web服务器

Mac或者Linux直接在Terminal里在GOPATH/src目录选执行bee new '项目名称'即可

## 进入GOPATH/src目录
cd ${GOPATH}/src
## 新建项目
bee new httpProject

在Windows下就在GOPATH/src目录下打开cmd执行bee new httpProject即可

执行完之后可以在GOPATHsrc目录下看到新建了一个非常标准的MVC项目

默认的新建项目肯定不能符合我们的需求,所以我们要稍加改进

我们先在router/router.go中的init方法里添加一个路由,用来处理请求

beego.Router("/sendhttp", &controllers.MainController{})

再到controllers里的default.go文件中,添加如下代码,熟悉MVC的读者大人肯定知道控制器接受用户的输入并调用模型和视图去完成用户的需求

所以我们得完善一下控制器收到请求后的处理,在这里我加了一个GET请求与POST请求

// Get 请求方法
func (c *MainController) Get() {
    c.Data["Website"] = "beego.me"
    c.Data["Email"] = "NaoNao@gmail.com"
    c.TplName = "index.html"
}

// Post 请求方法
func (c *MainController) Post() {
    c.Data["Website"] = "NaoNao"
    c.Data["Email"] = "AdolfYin@gmail.com"
    c.TplName = "naonao.html"
}

代码的意思就是GET请求返回index.html页面,POST请求返回naonao.html页面

所以我们还需要再到view里,添加index.html以及naonao.html文件

index.html文件里的完整内容大家去github上看好了,因为贴这种代码极其影响阅读体验。index.html地址

html里的关键代码如下,就是四种表单的提交

<p>GET方法默认提交</p>
    <form action="/sendhttp" method="GET"> 
    </form>

<p>POST方法默认提交</p>
    <form action="/sendhttp" method="POST">
    </form>

<p>POST方法以application/x-www-form-urlencoded提交</p>
    <form action="/sendhttp" method="POST" enctype="application/x-www-form-urlencoded"> 
    </form>

<p>POST方法,以multipart/form-data提交</p>
    <form action="/sendhttp" method="POST" enctype="multipart/form-data"> 

待会我们再用wireshark抓包工具来看,这四种不同的提交方式到底有何不同

好啦,说到这,我们已经完成了环境的搭建,Web服务器的搭建以及请求和响应方式

不过在运行Web服务器和抓包之前,我得再说点HTTP里form表单的一些基础知识,不然待会说抓包的时候,你可能会一脸懵逼

Form表单与HTTP的关系

关于form表单,它有三个核心的属性,分别是actionmethodenctype,这三个属性,都是与发起HTTP协议时相关联的

  • action:提交表单时,发起一个HTTP请求,action用来表示请求的URI
  • method:发起HTTP请求时,请求的方法是什么,比如是用GET还是POST
  • enctype:在POST请求方法下,对表单内容在请求包体中的编码格式,默认为application/x-www-form-urlencoded

actionmethod上面这样简单一提,我想大家心里都清楚怎么使用了,我就说下enctype的属性好了

application/x-www-form-urlencoded方式下,我们的数据会被编码成以&分隔的键-值对,同时以=分隔键和值,也就是我们常说的key=value的形式

除了上面这种默认形式,还有multipart/form-data方式,这种方式提交的表单,我们的数据分隔之后,会以boundary开头,最后以last boundary结尾。其中每一个部分的描述,皆有HTTP头部描述子包体,比如Content-Type。主要应用一种比较复杂的结构体编码

我们再重点看下multipart/form-data的提交方式

Content-Type来指明这是一个多表述包体,待会在wireshark中抓包我们就能看到
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryWiz1KWG5b5uvEUJR\r\n

这种提交方式下,每一个文本输入,每一个单选框/复选框,每一个文件,都是作为一个独立的资源表述的。如果不清楚HTTP的表述,可以看我之前分享的文章HTTP:资源是怎么协商、表述的?

boundary分隔符的格式在ABNF语法中的定义为0*69<bchars> bcharsnospace

这是什么意思呢?这表示通过0~69(0*69)个字符(bchars)作为分隔符,也就是说最多不能超过70个字符

而这字符支持的格式(bcharsnospace),可以为DIGT/ALPHA/'/(/)/+/-/_/,/.///:/=/?

其中DIGT是数字的意思,ALPHA代表字母

所以各位自己抓包的时候,可以看看你们自己看到的分隔符是长啥样的,偷懒的话,就回过头去看看我抓的吧

开始抓包实践

好啦,了解了form表单的HTTP关键属性,热身运动终于结束了。我们现在来运行我们的Web服务,来看一下我们的简单演示

现在我们可以在${GOPATH}/src/http-study-go目录下,使用go run main.go指令,即可运行我们刚刚搭建的Web服务器

用浏览器打开localhost:8080,即可访问我们刚刚搭建的网站

接着我们打开wireshark,找到我们本机的局域网环境。如果不知道是哪一个,可以在打开wireshark后,打开我们自己刚刚搭建的网站localhost:8090,有网络波动图形的,就是我们需要监视的网络

比如我下面截图的这个,(注意:每台电脑上的名称不一样,不要盲目抄作业)

想看看浏览器输入URI后发生了什么事情的,可以在找我们的本机网络后,用wireshark监视着,再打开浏览器输入localhost:8080打开我们自己的Web服务器。这样我们就能很清楚的看到TCP的三次握手(如下图)

以后人家问你浏览器输入URI按下回车后发生了什么事情,心里也有数了,看再多文章都不如自己动手试一试,当然了,这个不是今天的重点,今天就只提一下可以怎么看

继续回到之前的内容,我们来看看form表单的提交是如何使用HTTP协议的

GET提交

我们先来看看GET提交是怎么一回事

我们先打开Chrome浏览器的开发者工具(F12),在使用GET方式提交表单,看看Network面板里是什么数据

我们可以看到发送了一个GET请求,将我们在表单中输入的内容变成了QueryString的形式请求了URI

我们点击一下旁边的view Source,可以看到我们表单里填写的数据,其实是以UTF-8的编码格式进行的传输

我们再来看看wireshark中的抓包情况,看看是如何表现的,先找到我们刚刚发出的请求,点击即可查看HTTP请求的内容

我们可以看到比Chrome中更详细的信息,最下面的蓝色区域,对应的是请求URI的Refere内容,左侧的蓝色区域是标准的ABNF语法,有兴趣的可以去了解了解

POST提交

好了,我们再来看看不指定enctypePOST提交又发生了什么,

在这儿我就不贴Chrome里的Network面板内容了,直接展示wireshark中的内容了。需要注意的地方我都用红线圈出来了

可以看到,跟GET提交相比,POST多了一个包体,点开Content-Length,我们可以看到请求的URI里已经没有参数了,并且Content-Type里展示了我们的内容编码方式

默认为application/x-www-form-urlencoded,后面的\r\n是换行符的意思

第三种POST提交并指定enctype=application/x-www-form-urlencoded的提交方式我在这就不多说了

我们重点来看看enctype=mulipart/form-data这种方式的提交

因为我们采用mulipart的方式请求,在请求中含有大量包体,在Chrome的Network面板中是看不到,所以我还是直接放wireshark抓取到的报文内容吧

wireshark中找到我们请求的HTTP报文,我们可以看到,请求内容多了两个

Content-Type中,多了一个boundaryboundary后面的分隔符是以/r/n结尾的,并且在Content-Length中,最后我们可以看到分隔符是以--/r/n来结尾

多的另外一个东西,往下翻我们可以看到MIME multipart Media Encapsulation,这是包体中包含的资源文件

点开后我们可以发现,首先会有一个First boundary,里面的分隔符是以/r/n结尾,表示所有资源的开始。到最后会有一个Last boundary是以--/r/n结尾,表示所有资源的结束

其中每一个资源都有着一个分隔符,每一个在分隔符后面都是以\r\n结尾,直到最后一个资源,在\r\n的前面多了2个-,意味着整个请求包体的结束

点开其中的资源文件,会发现每一个资源文件都包含了Content-Disposition这个字段,因为这个是必须要有的,表示这个资源的name

如果是非文本框之类的东西,还会有一个Contenty-Type用于表示这个资源的类型

以我提交的文本文件来说一下,图中我圈出来了

可以看到Content-Type告诉我,上传的是一个text/plain的文件,点开下面的text data,可以看到里面传输的内容为NaoNaoChiYu

所有的资源文件传输完后,最后会以一个Last boundary的分隔符并加上--/r/n来结尾

这就是一个完整的表单提交发生的HTTP传输

写在最后

最后给大家留一个问题。如果Form表单中的字段,没有name,只有id,资源中的Content-Disposition内容是什么?是否还会有这个内容?如果没有的话,服务器还能接收到这个资源文件么?

好了,今天借着说Form表单提交的方式,给大家说了下怎么搭建自己的Web服务,以及如何抓包

之后我会补一篇HTTP用ABNF语法表述的入门文章,因为我说过,我会以实践的方式来写HTTP协议的系列,所以后面的文章会有更多的内容牵扯抓包

如果看不懂ABNF语法,那看抓包的内容真的就是看天书了

马上月底了,下一篇文章就不写技术干货了,分享点别的内容。

毕竟收租时间到了,要开赞赏了。写技术干货都没人看,没人看就没人交租了…在外面出差过着9 11 7的日子,我还保持了稳定的每周二更新…这俩月我自己都佩服我自己了


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:aside section ._1OhGeD

查看原文:与HTTP的第一次亲密接触

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

745 次点击  
加入收藏 微博
上一篇:Go-interface
下一篇:Go-for range
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传