zoukankan      html  css  js  c++  java
  • 【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

     

     

  • 相关阅读:
    ubuntu安装 scala
    提交jar作业到spark上运行
    在IDEA上用python来连接集群上的hive
    spark在eclipse上配置
    【Spring AOP】Spring AOP的使用方式【Q】
    【Spring 源码】ApplicationContext源码
    【Spring 源码】Spring 加载资源并装配对象的过程(XmlBeanDefinitionReader)
    【Spring Cloud】Spring Cloud使用总结
    【坑】不要使用各种框架提供的内部List
    Lombok的使用
  • 原文地址:https://www.cnblogs.com/straycats/p/14461357.html
Copyright © 2011-2022 走看看