Python写自动化之构造Multipartform-data发请求

在HTTP协议的规范中会将http请求分为三个部分:状态行,请求头,请求体。在发送HTTP请求时,需要在请求头中注明发送的方法,这些方法包括:OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT。其中GET和POST是最为普遍被使用的。有关POST和GET的区别,知识库中已经有同学进行了表述,这里主要介绍一下multipart/form-data请求具体是怎么一回事。

 在普通的HTML Form Post请求中,它会在头信息里使用Content-Length注明内容长度。头信息每行一条,空行之后便是Body,即“内容”(entity)。它的Content-Type是application/x-www-form-urlencoded,这意味着消息内容会经过URL编码,就像在GET请求时URL里的QueryString那样。以搜狗浏览器扩展升级的请求为例:

技术分享

在早期的HTTP Post是不支持文件上传的,编程开发带来很多问题。所以在《RFC 1867 -Form-based File Upload in HTML》中增加了用以支持文件上传的类型。即Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此发送post请求时,表单<form>属性enctype共有二个值可选,这个属性管理的是表单的MIME编码:

  1. application/x-www-form-urlencoded(默认值)
  2. multipart/form-data

其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype="application/x- www-form-urlencoded".

 

那么multipart/form-data请求有哪些特征呢?

1、multipart/form-data的基础方法是post

2、multipart/form-data与普通post方法的不同之处:请求头,请求体。

3、multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,且其值也必须规定为multipart/form-data,同时还需要规定一个内容分割符用于分割请求体中的多个post的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了。

4、multipart/form-data的请求体也是一个字符串,不过和普通post的请求体不同的是它的构造方式,post是简单的name=value值连接,而multipart/form-data则是添加了分隔符等内容的构造体。

 

通过Fiddler截取发送的请求包内容如图:

技术分享

本次12306预约抢票功能的测试过程中,在针对“提交预约单”的接口进行测试时,客户端向服务端提交信息的方式就是multipart/form-data。为了提高测试效率,便利用Python构造网络请求来针对接口进行了测试。具体的代码如下:

# coding=gbk

import urllib2;

import json;

 

def post_data():

    parameters = {'id': '', 'user': { 'username': '', 'password': '' }, 'query': { 'fromStation': 'beijing', 'fromStationText': 'shanghai' }}

    jdata = json.dumps( parameters )

    post_multipart( 'http://extention.ie.sogou.com/mm_12306/prebook', jdata )

   

def post_multipart( url , fields ):

 

    content_type, body = encode_multipart_formdata( "data", fields )

 

    req = urllib2.Request( url, body )

    req.add_header( "User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 SE 2.X MetaSr 1.0)" )

    req.add_header( "Accept", "*/*" )

    req.add_header( "Accept-Language", "zh-CN,zh;q=0.8" )

    req.add_header( "Accept-Encoding", "gzip,deflate,sdch" )

    req.add_header( "Connection", "keep-alive" )

    req.add_header( "Content-Type", content_type )

    req.add_header( "User-Agent1", "SogouMSE" )

   

    try:

        response = urllib2.urlopen( req )

        the_page = response.read().decode( 'utf-8' )

        print the_page

        return the_page

    except urllib2.HTTPError, e:

        print e.code

        pass

    except urllib2.URLError, e:

        print str( e )

        pass

 

def encode_multipart_formdata( key, value ):

 

    BOUNDARY = '----------ThIs_Is_tHe_bouNdaRY_$'

    CRLF = '\r\n'

    L = []

    L.append( '--' + BOUNDARY )

    L.append( 'Content-Disposition: form-data; name="%s"' % key )

    L.append( '' )

    L.append( value )

 

    L.append( '--' + BOUNDARY + '--' )

    L.append( '' )

    body = CRLF.join( L )

    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY

    return content_type, body

   

if __name__ == '__main__':

    post_data();



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。