https://blog.csdn.net/weixin_44268320/article/details/106423951

  1. POST /upload HTTP/1.1
  2. Host: 127.0.0.1:8080
  3. Content-Type: multipart/form-data; boundary=-----WebKitFormBoundaryXxfiMGIApglCZPgJ
  4. -------WebKitFormBoundaryXxfiMGIApglCZPgJ
  5. Content-Disposition: form-data; name="file"; filename="pstree.png"
  6. Content-Type: image/png
  7. -------WebKitFormBoundaryXxfiMGIApglCZPgJ
  8. Content-Disposition: form-data; name="token"
  9. bR3KfLEVxQNHg3K8FZYKJDJIMHBgBDe5hMjUu6gJ:aE2enHspPmBIdi9nbLYg5sNv_7Q=:eyJzY29wZSI6ImxpbnV4LW1lZGlhLWtub3dsZWRnZS1pdHVrbm93bi1jbjpwc3RyZWUucG5nIiwiZGVhZGxpbmUiOjE2MzcyMTUwMzc4ODUsInJldHVybkJvZHkiOiJ7XCJrZXlcIjpcIiQoa2V5KVwiLFwiaGFzaFwiOlwiJChldGFnKVwiLFwiZnNpemVcIjokKGZzaXplKSxcImJ1Y2tldFwiOlwiJChidWNrZXQpXCIsXCJuYW1lXCI6XCIkKHg6bmFtZSlcIn0iLCJmaWxlVHlwZSI6MCwiaW5zZXJ0T25seSI6MX0=
  10. -------WebKitFormBoundaryXxfiMGIApglCZPgJ
  11. Content-Disposition: form-data; name="key"
  12. pstree.png
  13. -------WebKitFormBoundaryXxfiMGIApglCZPgJ
  14. Content-Disposition: form-data; name="fname"
  15. pstree.png
  16. -------WebKitFormBoundaryXxfiMGIApglCZPgJ--

文件上传

做接口测试怎么能少的了文件上传功能呢? 来看下使用 REST Client 编写文件上传请求:

语法介绍

REST Client 文件上传请求比普通的请求要麻烦点,因为我们需要严格的定义请求协议和格式,下面是文件上传语法示例:

单文件上传语法:

  1. POST /API
  2. Host: $domain
  3. Content-Type: multipart/form-data; boundary=$boundary
  4. --$boundary
  5. Content-Disposition: form-data; name="file"; filename="pstree.png"
  6. Content-Type: image/png
  7. < /filepath/pstree.png
  8. --$boundary--

多文件上传语法:

  1. POST /API
  2. Host: $domain
  3. Content-Type: multipart/form-data; boundary=$boundary
  4. --$boundary
  5. Content-Disposition: form-data; name="image"; filename="pstree.png"
  6. Content-Type: image/png
  7. < /filepath/pstree.png
  8. --$boundary
  9. Content-Disposition: form-data; name="txt"; filename="example.txt"
  10. < /filepath/example.txt
  11. --$boundary--

单文件与多文件语法是一致的,唯一的区别就是边界的定义,注意看两则的区别,下面来说下:

注意看 Content-Type: multipart/form-data; boundary=$boundary

Content-Type: multipart/form-data; 指定的是请求类型协议,就是以 form 表单形式形成流输出,而 boundary=$boundary 则是定义二进制流文件边界。

boundary 后面的值定随意指定的,可以是任意字符串。如 WebKitFormBoundary--WebKitFormBoundaryXdfsd 都是可以的。一定要注意,这里定义的边界是用于限制接下来的二进制流数据。

接下来需要注意看如何去二进制流数据,它的格式为(注意看空行,必须严格按照如下格式):

  1. --$boundary
  2. Content-Disposition: form-data; name="file"; filename="pstree.png"
  3. Content-Type: image/png
  4. < /filepath/pstree.png
  5. --$boundary--

二进制流数据是在两个 $boundary 之间定义,注意起始和结尾格式。比如我们定义的 $boundary 值为 WebKitFormBoundary,那么上面的内容就是:

  1. --WebKitFormBoundary
  2. Content-Disposition: form-data; name="file"; filename="pstree.png"
  3. Content-Type: image/png
  4. < /filepath/pstree.png
  5. --WebKitFormBoundary--

在边界起始和结束中间的内容就是需要我们定义的二进制数据,第一行就是定义文件内容(注意与起始边界之间不能有空行):

  1. Content-Disposition: form-data; name="file"; filename="pstree.png"

name 指定的是服务端接收的 key,这个其实就是 Form 表单的 name 属性指定的值:

  1. <body>
  2. <div>
  3. <input type="file" name="image">
  4. </div>
  5. </body>

filename 就是服务端收到的文件的原始文件名,这个值指定的文件名不需要与真实的文件名一致,但文件名后缀最好保持一致!

一定要注意文件定义与边界之间不能有空行,比如写成下面的形式是不行的:

  1. --WebKitFormBoundary
  2. <== 这里不能有空行
  3. Content-Disposition: form-data; name="file"; filename="pstree.png"

Content-Type: image/png 定义的是你上传文件的类型,可以不指定,同样的与 Content-Disposition 之间不能有空行!

接下来需要空一行进行指定文件,紧接着就是二进制文件结束边界,格式为:

  1. < $filepath
  2. --$boundary--

$filepath 是你机器上的文件路径,可以是相对地址也可以是绝对地址。紧接着就是二进制流数据结束边界!比如我们示例中定义的 $boundary 值为 WebKitFormBoundary,那么结束边界就是:

  1. --WebKitFormBoundary--

那么多文件上传呢?唯一的区别就是边界!要注意,一个文件就对应一个 $boundary。但是结束边界只会有一个:

  1. --$boundary <== 第一个文件
  2. Content-Disposition: form-data; name="image"; filename="pstree.png"
  3. Content-Type: image/png
  4. < /filepath/pstree.png
  5. --$boundary <== 第二个文件
  6. Content-Disposition: form-data; name="txt"; filename="example.txt"
  7. < /filepath/example.txt
  8. --$boundary-- <== 在最后一个文件结尾处加结束边界

单文件请求示例

上面介绍了相关协议,下面就来稍微修改下来做个上传测试:

  1. POST /upload
  2. Host: 127.0.0.1:8080
  3. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
  4. ------WebKitFormBoundary
  5. Content-Disposition: form-data; name="file"; filename="pstree.png"
  6. Content-Type: image/png
  7. < /Users/mingrn97/Desktop/pstree.png
  8. ------WebKitFormBoundary--
注意
上面定义的边界为 ----WebKitFormBoundary,那么下面定义的二进制流数据起始边界就要在左边加上 --,结束边界就要在两边都加上 --

下面是服务端 Debug 截图:

image.png

name 没什么好说了,来看下 filename。这就是之前请求时指定的文件名,如果你请求时定义的 filename 值为 xx.png 那么这里得到的 flename 就是 xx.png。

接着看我们在服务端接收的类型就是 image/png,这是因为我们在定义二进制流时指定了数据类型:Content-Type: image/png,如果不指定我们服务端收到的就是一个 NULL。

多文件请求示例

那如何同时上传多个文件呢?

注意多文件上传分为两种,一种是同一个 name 多文件,第二种是每个文件都有一个 name。对应 HTML 文件上传组件如下:

  1. <!-- 多组件上传 -->
  2. <body>
  3. <div>
  4. <input type="file" name="image">
  5. <input type="file" name="file">
  6. </div>
  7. </body>
  8. <!-- 同一组件上传多文件 -->
  9. <body>
  10. <div>
  11. <input type="file" multiple>
  12. </div>
  13. </body>

这两种形式大家肯定都不陌生,来看下怎么写:

多组件上传示例:

  1. POST /upload
  2. Host: 127.0.0.1:8080
  3. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
  4. ------WebKitFormBoundary
  5. Content-Disposition: form-data; name="file"; filename="example.txt"
  6. Content-Type: text/plain
  7. < /Users/kali/example.txt
  8. ------WebKitFormBoundary <=== 注意这里
  9. Content-Disposition: form-data; name="image"; filename="pstree.png"
  10. Content-Type: image/png
  11. < /Users/kali/pstree.png
  12. ------WebKitFormBoundary--

多文件上传唯一要注意的是两个二进制流数据之间使用 --$boundary 做分割,而不是 --$boundary-- 。相应的,以 Java 为例。后台就需要定义两个 MultipartFile,一个指定名称为 file 一个指定名称为 image 就好了(如下图)。当然如果不想麻烦可以直接使用 MultipartHttpServletRequest 对象接收然后循环便利文件流即可~

Screen Shot 2021-11-18 at 10.20.18.png

单组件上传示例

但组件上传多文件与多组件上传唯一的区别就是 name 值。我们只需要使 name 值一样即可:

  1. POST /upload
  2. Host: 127.0.0.1:8080
  3. Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
  4. ------WebKitFormBoundary
  5. Content-Disposition: form-data; name="files"; filename="example.txt"
  6. Content-Type: text/plain
  7. < /Users/kali/example.txt
  8. ------WebKitFormBoundary
  9. Content-Disposition: form-data; name="files"; filename="pstree.png"
  10. Content-Type: image/png
  11. < /Users/kali/pstree.png
  12. ------WebKitFormBoundary--

注意看 name 值,两个都是 files(注意一定要保证 filename 值不同)。这样后台服务代码直接使用一个数组或列表接收即可:

Screen Shot 2021-11-18 at 10.26.48.png