http的multipart/form-data请求

简单的HTTP POST

使用post请求向http服务器提交数据,通常是使用form表单提交:

<html>  
    <head>
        <title>x-www-form-urlencoded</title>
    </head>

    <body>
        <form action="http://timd.cn:9092/" enctype="application/x-www-form-urlencoded" method="post">
            <input type="text" name="text1" /><br/>
            <input type="text" name="text2" /><br/>
            <input type="submit" value="submit" />
        </form>
    </body>
</html>  


提交时,会向服务器发送类似下面的HTTP请求(已去掉不相关的请求头信息):

POST / HTTP/1.1  
Content-Length:23  
Content-Type:application/x-www-form-urlencoded  
Host:timd.cn:9092

text1=this-is-text1&text2=this-is-text2  


请求体的Content-Typeapplication/x-www-form-urlencoded,这意味着请求体会经过URL编码,就像GET请求时URL里的QueryString一样。


使用multipart/form-data请求上传文件

为了支持文件上传,ietf在1995年出台了rfc1867,也就是《RFC 1867-Form-based File Upload in HTML》Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此在发送POST请求的时候,表单<form>enctype属性共有两个值可选,这个属性管理的是表单的MIME编码:

 ①application/x-www-form-urlencoded(默认值)
 ②multipart/form-data


默认值是:enctype="application/x-www-form-urlencoded"

multipart/form-data请求有如下特点:

  • multipart/form-data的基础方法是POST,也就是说它是由POST方法来组合实现的
  • multipart/form-data与POST方法的不同之处:请求头和请求体
  • multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,且其值必须是multipart/form-data,同时还要规定一个内容分隔符,用于分隔请求体中的多个POST内容。具体的头信息如下:
    Content-Type: multipart/form-data; boundary=${bound}
    其中${bound}是一个占位符,代表内容分隔符,可以任意规定,但是不能出现在上传的文本内容中。

使用multipart/form-data上传文件的例子:

<html>  
  <head><title>multipart</title></head>
  <body>
    <form action="http://timd.cn:9092/" enctype="multipart/form-data" method="post">
    <input type="file" name="file1" /><br/>
    <input type="file" name="file2" /><br/>
    <input type="submit" value="submit" />
    </form>
  </body>
</html>  


提交时,会向服务器发送类似下面的HTTP请求(已去掉不相关的请求头信息):

POST / HTTP/1.1  
Content-Length:646  
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryPKGQqydAiTdFABKl  
Host:timd.cn:9092

------WebKitFormBoundary6IWwukBBXn34AzqG
Content-Disposition: form-data; name="file1"; filename="a.py"  
Content-Type: application/octet-stream

import time  
------WebKitFormBoundary6IWwukBBXn34AzqG
Content-Disposition: form-data; name="file2"; filename="a.html"  
Content-Type: text/html

<html>  
  <head><title>Upload File</title></head>
  <body>
    <form action='http://timd.cn:9092/' enctype="multipart/form-data" method='post'>
    <input type='file' name='file1'/><br/>
    <input type='file' name='file2'/><br/>
    <input type='submit' value='submit'/>
    </form>
  </body>
</html>  
------WebKitFormBoundary6IWwukBBXn34AzqG--


可以看出,浏览器自动生成的内容分隔符是----WebKitFormBoundary6IWwukBBXn34AzqG,同时在这个请求体中,有两部分内容。每一个部分都是以--加上内容分隔符开始的,然后是该部分内容的描述信息,然后是\r\n,然后是具体内容。如果传送的内容是一个文件的话,那么还会包含文件名信息,以及文件内容的类型。最后会以--${bound}--结尾。

下面是一个python的例子

# test_multipart.py

import tornado.web  
import tornado.ioloop

class MainHandler(tornado.web.RequestHandler):  
    def post(self, *a, **kw):
        self.write(self.request.body)

    def get(self, multipart='multipart'):
        if multipart == 'multipart':
            self.write("""
<html>  
  <head><title>multipart</title></head>
  <body>
    <form action="http://timd.cn:9092/" enctype="multipart/form-data" method="post">
    <input type="file" name="file1" /><br/>
    <input type="file" name="file2" /><br/>
    <input type="submit" value="submit" />
    </form>
  </body>
</html>  
            """)
        else:
            self.write("""
<html>  
    <head>
        <title>x-www-form-urlencoded</title>
    </head>

    <body>
        <form action="http://timd.cn:9092/" enctype="application/x-www-form-urlencoded" method="post">
            <input type="text" name="text1" /><br/>
            <input type="text" name="text2" /><br/>
            <input type="submit" value="submit" />
        </form>
    </body>
</html>  
            """)

if __name__ == "__main__":  
    app = tornado.web.Application(
        [
            (r'/(?P<multipart>.*)', MainHandler),
        ]
    )

    app.listen(9092)
    tornado.ioloop.IOLoop.instance().start()

感谢浏览tim chow的作品!

如果您喜欢,可以分享到: 更多

如果您有任何疑问或想要与tim chow进行交流

可点此给tim chow发信

如有问题,也可在下面留言: