【http/https】Content-Type的boundary

===============================================

 2021/2/28_第1次修改                       ccb_warlock

 

===============================================

写这篇文章的起因原本只是想作为一个问题的解决方案,但是经过一些测试后,发现问题并不是一个配置去掉这么简单。

 


一、问题与解决方案

起初我在整理java项目的接口文档时,整理到了文件上传的接口。作为刚接触java没多久的我,为了保证功能逻辑没有写错,于是调试该接口。

 

key(headers) value
Content-Type multipart/form-data

结果接口提示“Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found”的错误。

 

查了资料后了解到,使用post上传文件时,不仅需要指定mutipart/form-data来进行编码,还需要在Content-Type中定义boundary作为表单参数的分隔符。

 

于是加上了自定义的boundary内容:

key(headers) value
Content-Type multipart/form-data; boundary=----WebKitFormBoundary7TMYhSONfkAM2z3a

 

结果接口又提示“Required request part 'file' is not present”(其中file就是body中上传文件对应的key)。

 

 

由于我不会写前端,没法通过写个前端页面使用浏览器请求,从而绕过postman。而我之前用c#其实也写过类似的功能,于是我用.NET 5构建了一个上传文件的接口,再用postman请求。

 

首先我也是通过postman发送没有boundary的请求,结果和java一样,提供了类似的报错信息(Missing content-type boundary.)。

key(headers) value
Content-Type multipart/form-data

 

接着将自定义的boundary加上,再次请求,结果和java一样,提供了类似的报错信息(Unexpected end of Stream, the content may have already been read by another component.)。

key(headers) value
Content-Type multipart/form-data; boundary=----WebKitFormBoundary7TMYhSONfkAM2z3a

 

这样就基本排除了语言或框架的差异,确实调用存在问题。

 

 

针对这个问题,我请教了级别更高的java同事也得不到解决方案。直到看到了这篇文章(https://blog.csdn.net/sun_977759/article/details/88868509)终于解决。

 

解决方案:

上传文件的请求中去掉headers中自定义的content-type。

但是问题的原因并没有解决方案那么简单,实际是因为postman(5.5.5)的bug引起了这个问题,下面具体描述。

 


二、思考与验证

这个问题是解决了,但是又让我有了新的疑问,为什么用postman上传文件不能设置头信息content-type?

 

根据http标准定义,用户可以在发送上传文件请求时自定义boundary。看资料,别人对这块的理解也是用户可以自定义boundary(https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data)。

 

正当搜索了一圈资料找不到答案时,偶然看到这个issue(https://github.com/postmanlabs/postman-app-support/issues/6140

 

难道是老版本postman存在bug?于是下了最新的postman(8.0.6)进行测试,测试结果符合预期,即根据我定义的boundary作为分隔符。

 

postman(8.0.6)的抓包结果

5.5.5版本的postman由于我更新了插件后无法回退进行测试(5.5.5的桌面版在官网下不到),故我通过下了桌面客户端做了测试。

发现功能虽然正常,但是请求中boundary并不是我定义的内容,而是postman自己随机生成了字符串作为boundary。

 

postman(6.7.4)的抓包结果

postman(5.5.3)的抓包结果


三、总结

1)请求上传文件的接口时,需要使用post;

2)请求上传文件的接口时,需要在header信息中的Content-Type指明数据以mutipart/form-data进行编码,同时定义boundary作为分隔符(如果没有指定Content-Type,浏览器或postman会自动生成);

3)java异常中的“the request was rejected because no multipart boundary was found”、.NET中的“Missing content-type boundary.”,一般是Content-Type中没有定义boundary引起的;

4)java异常中的“Required request part 'file' is not present”(其中file就是body中上传文件对应的key)、.NET中的“Unexpected end of Stream, the content may have already been read by another component.”在我遇到的这个问题中是因为postman(5.5.5)在请求时分隔表单的分隔符使用了自动生成的字符串、而header使用了用户自定义的内容,导致接口根据头信息的boundary无法解析表单的内容。

 


参考资料:

1.https://blog.csdn.net/sun_977759/article/details/88868509

2.https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data

3.https://github.com/postmanlabs/postman-app-support/issues/6140

 

 

原文地址:https://www.cnblogs.com/straycats/p/14461357.html