Skip to content

传参与抓包(必看)

廖子尧 edited this page Jul 7, 2017 · 1 revision

在分析之前,如果你不懂http协议,一定要看下面的博客,否则,后面的内容看不懂:

这是网上一些关于Http协议的讲解

看完后,开始正文!!

这里分析的是okgo的不同的传参代码的写法,与对应的抓包截图,截图主要展示的是请求参数,不展示响应参数,关于抓包数据的看懂,请自行看http协议。

1. 上传请求头

请求头不支持中文,不要尝试传递中文信息,否则会出现异常。

2. GET、HEAD等无请求体的传参方式

注意以下几点:

  1. GET、HEAD这种没有请求体的请求方式,他们的参数是会默认拼接在url后面的,就像截图中那样,最终请求的时候会默认在url的最后面,加上?表示参数开始,然后用&号连接各个参数,每个参数键值对使用=号连接。这个就是使用url的传参方式。
  2. params支持第三个参数,表示如果key相同,后面的参数是否覆盖前面的参数,默认为true,即默认覆盖,原因是这种行为在你需要修改参数的值的时候特别有效,你只需要重新添加一个新的值就行了,而不需要关心他之前是否有值。如果你明确不想覆盖,可以传递false,就像截图中的效果,该参数会出现多次。
  3. 请求参数是支持中文的,不需要自己转码,请求的时候发现中文变成了%后面跟十六进制的表示方法,这不是乱码,注意,这不是乱码,这不是乱码,这种编码方式叫URL编码,这是一种规范,是http传递中文的规范,同样的,服务端接收到这种参数后,第一步是使用URL解码,然后才能拿到正确的参数,如果你不知道什么是URL,强烈建议你自己百度一下。这里有个在线转换URL编码的网站,不信的话你可以复制你认为的乱码进来试试,URL在线编解码转换

3. POST, PUT, DELETE 等有请求体的传参

这里就分很多情况了

情况1、请求参数无文件

和上面的例子一样,我们只是简单的把get换成了post,我们看看抓包的结果,分析如下:

  1. 和get请求相比,url没有拼接任何参数,传进来的url是什么,最后请求的url就是什么。
  2. 请求头多了一个字段叫Content-Type:application/x-www-form-urlencoded,这个表示当前请求是http普通的表单请求,并且请求的参数经过了URL编码。这个请求头不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  3. 我们的参数跑到了最底下,这部分就是http协议中的请求体部分,我们发现他的参数的拼接方式和上面说到的GET请求的拼接方式一样,唯一不同的就是参数的位置不一样,GET是拼接在URL后面的,POST是在请求体里面的。

情况2、请求时候想在url上也拼接参数

通过情况1我们知道,正常的post等有请求体的请求,参数都是在请求体中的,有些服务端比较奇怪,不仅请求体需要参数,url上希望也拼接参数,怎么办呢?

当然okgo提供了简单的解决办法,只需要加上.isSpliceUrl(true)方法,就可以在当前请求的url上拼接上参数了,抓包截图看的很清楚。不仅请求体有参数,url上也有参数了,默认情况下,这个参数是false,只在你需要的情况下拼接就好了。

情况3、请求参数有文件

关于这里,就得说明很多了,我们与上面没有文件的情况进行对比,我一点点说。

  1. 同样url上并没有拼接任何参数,传进来的url是什么,最后请求的url就是什么。
  2. 请求头的一个字段变成了Content-Type:multipart/form-data;boundary=36e41be3-1395-40ff-8219-0824843b833c,这个字段前面的multipart/form-data表示这是个mutipart格式的表单上传,后面的boundary表示每部分的分隔符是后面那串特殊的字符,这个字符每次请求都是随机生成的,他的作用就是表示下面请求体按这个分隔符分割。这个请求头不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  3. 我们发现仅仅加了文件,请求体的变化相当大,变的特别复杂了,我在图中圈出来了4个部分,依次按顺序对应了代码中的四个params,我们发现,他们都是以--开始,加一些特殊的属性和一个空行,空行下面是我们真正的参数,然后在整个请求体的最后面,也就是4个参数的最后,还有个----的结构,表示请求体结束了,后面没有参数了,没错,这就是我们说的文件与参数共同上传的multipart表单上传。
  4. 我们发现文件参数与普通的参数唯一区别就是多了一个filename,和一个content-type属性,这个filename就是你文件真正的名字,这个content-type就是你这个文件的MIME类型。而无论文件参数还是普通参数都有的一个name属性,这个才是这个参数的key,需要特别注意的是不要把文件的名字和文件的key搞混了。
  5. 这一切的格式拼接都是okgo自动完成的,你不要关心是不是要自己设置整个请求的Content-Type为multipart/form-data,也不需要关心每个文件的Content-Type是不是他们自己的,你会发现okgo很智能的,也很正确的传递了每个参数,你也不需要关心这个格式为什么是这样,或者正不正确,因为这是Http协议的标准写法,他必须是这样。
  6. 需要注意的是,文件1在抓包的内容中显示了他的内容,没有变成乱码,因为他是个文本文件,可以直接显示,而文件4是个png图片,图片如何能转成文本显示出来呢,所以看着是乱码,但是不重要,因为服务端只要用字节流去接,依然会得到正确的结果。

为了让你们更加了解上传的一些作用,我这里放一张我以前画的图,图中的OkHttpUtils就是OkGo,因为OkGo以前就叫OkHttpUtils,主要是我实在是不愿意再画一张图了,大家凑合看。

情况4、请求参数没有文件,依然想用multipart上传

通过情况一的介绍,我们知道正常没有文件的情况下,请求头的值是如下值:Content-Type:application/x-www-form-urlencoded,并且参数都是使用&符号拼接起来的,但有时候,有些服务端就要无论你是否有文件,都要使用multipart方式上传,怎么办呢?

解决办法就是请求的时候多加一个参数,.isMultipart(true),表示当前这个请求强制使用multipart方式上传,当然有文件的时候,默认就是true了,就算你改成false也没用,因为文件只能用multipart方式上传。所以我们改完后看到了请求体里面那段复杂格式的代码。

情况5、一个key传多个值,或者多个文件怎么传

因为我们传了文件,所以格式自动变成了multipart,我们可以看到即使我们写了相同的key,真正传参的时候会将key对应的值拆开,每个值使用一样的key分别上传一遍。

警告!!!

特别要说明的是,当你使用了一个key传多个文件这种方式的时候,你很有可能碰到只有最后一个文件或者第一个文件上传成功了这种问题。这不是okgo的问题,这种问题的原因有以下几个:

  1. 服务端代码的写法并不支持一个key接收多个文件,特别是php后台,经常有人遇到,如果你发现你是这种情况,那么请把我的这篇分析文章给你的后台看,你们自己慢慢商量到底谁改。
  2. 你没看懂接口文档,你以为是一个key传多个文件,其实应该是一个key传一个文件。

4. up系列传参方式介绍

up系列与parmas系列都是上传参数,但是他们区别很大,主要原因如下:

  1. params是按照http协议来拼接参数的,不同的请求方式,不同的参数,都会导致最后上传到服务端的数据完全不一样,而且他们的拼接格式是不是受用户控制的,是严格的按照http协议来的。
  2. up系列是完全由用户控制的,你传什么参数,框架会原封不动的传递给服务端,不做任何修改,唯一可能发现变化的就是请求头,原因是okgo必须遵循http协议,最简化用户的操作,把那些公共的通用的行为自动完成。
  3. 以上介绍可知,up行为与params行为完全是两种不同的方式,所以他们传参是互不兼容的,如果同时存在两种方式,永远只会按照up系列的行为来,所有的params参数都不会上传。

1)upString()方法

这种方式注意以下两点:

  1. 该方法默认使用了Content-Type:text/plain;charset=utf-8这个请求头,不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  2. 这个方法是不需要传key的,你传的什么数据,就会原封不动的传递给服务器,所以你应该把你所有的参数都写这里面。

2)upJson()方法

这种方式注意以下两点:

  1. 该方法默认使用了Content-Type:application/json;charset=utf-8这个请求头,不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  2. 这个方法也是不需要传key的,你需要把你需要的所有参数都写到json里面,然后传递给服务器。

3)upFile()方法

这种方式注意以下两点:

  1. 该方法的Content-Type,会根据上传文件的后缀名自动匹配最合适的,我们传递的是个png图片,所以默认就匹配到了Content-Type: image/png,这个行为是okgo智能的,不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  2. 这个方法就是单纯的上传一个文件,什么其他的都不会上传。

4)upBytes()方法

  1. 该方法默认使用了Content-Type:application/octet-stream这个请求头,不要尝试自己修改,也不支持修改,就算你修改了,也不会生效。
  2. 这个方法也是不需要传key的,你需要把你需要的所有参数都转成byte[],然后传给服务器。

5)up系列与params系列混用的一个特殊用法

我们一直在说up系列与params系列方法不能混用,这里有个使用场景,服务端希望传递json传的同时,url上也需要拼接一些参数,但是我感觉手动在url上拼参数有点low,所以可以这么写:

  1. 使用params传递需要在url上拼接的参数
  2. 使用up系列传递你想上传的请求体参数
  3. 使用.isSpliceUrl(true),改变请求方式的行为,默认拼接url参数
  4. Content-Type请求头,与up系列的行为保持一致。

这样就可以把params的参数写到url中,up系列的参数写入请求体了。

!!!警告

不要无脑这么使用,不要以为params和up就这么可以共存,注意他们的实质,params的参数并没有出现在请求体中,只是我们用个取巧的办法把params拼接到url中了,所以,这么做之前,首先确定服务端是不是要你这么传递参数,如果不是,那就先了解服务端要你怎么传参。

写了这些基本上涵盖了绝大部分的传参方式和用法,以及对应的抓包截图,如果你对Content-TypeContent-Length这两个请求头还有疑问,这里有篇okgo的总结,可以看看,点击查看

Clone this wiki locally