• 【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

     

     

  • 相关阅读:
    Intellij IDEA 打开文件tab数量限制的调整
    Mysql处理中文乱码的问题
    MIT算法导论笔记
    算法导论-排序(一)-插入排序、归并排序
    leetcode题解:Search for a Range (已排序数组范围查找)
    leetcode 题解:Merge Sorted Array(两个已排序数组归并)
    leetcode题解:Construct Binary Tree from Inorder and Postorder Traversal(根据中序和后序遍历构造二叉树)
    leetcode题解:Construct Binary Tree from Preorder and Inorder Traversal (根据前序和中序遍历构造二叉树)
    c++11 std::prev、std::next、std::advance与auto 使用
    (转)指针的引用(*&)与指针的指针(**)
  • 原文地址:https://www.cnblogs.com/straycats/p/14461357.html
Copyright © 2020-2023  润新知