python模块介绍-httplib:HTTP协议客户端和HTTPS协议客户端

python模块介绍-httplib:HTTP协议客户端 

注意:httplib模块在Python3.0中已更名为http.client。2to3脚本会自动修改import当你的源代码转换时到3.0时。

httplib实现了HTTP和HTTPS的客户端协议,一般不直接使用,在python更高层的封装模块中(urllib,urllib2)使用了它的HTTP和HTTPS实现。其中HTTPS需要socket编译了SSL支持。HTTP类仅仅是和python1.5.2及以前的版本兼容,不推荐使用。

代码:Lib/httplib.py

接口

基本类

  • class httplib.HTTPConnection(host[, port[, strict[, timeout[, source_address]]]]) :

HttpConnection的实例表示与HTTP服务器的事务。实例化时需要传递主机和可选的端口号。如果没有端口号,试图以host:port格式从主机字符串提取,如果提取失败则使用默认的HTTP端口(80)。参数strict默认为false,表示在无法解析状态行时(status line)不能被HTTP/1.0或1.1解析时不抛出BadStatusLine异常;可选参数timeout表示即阻塞在多少秒后超时,如果没有给出默认使用全局超时设置。可选参数source_address表示HTTP的源地址(host, port)。

timeout为2.6添加,source_address为2.7添加。

1
>>>  import  httplib>>> h1  =  httplib.HTTPConnection( 'automationtesting.sinaapp.com' )>>> h1  =  httplib.HTTPConnection( 'automationtesting.sinaapp.com:80' )>>> h1  =  httplib.HTTPConnection( 'automationtesting.sinaapp.com' , 80 )>>> h1  =  httplib.HTTPConnection( 'automationtesting.sinaapp.com' , 80 , timeout = 10 )
  • class httplib.HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]])

HttpConnection的子类,使用SSL与安全服务器通信。默认端口为443。key_file是包含PEM格式私钥的文件名称。 cert_file中是PEM格式的证书链文件。

注意不支持验证服务器的证书。timeout为2.6添加,source_address为2.7添加。

  • class httplib.HTTPResponse(sock, debuglevel=0, strict=0)

实例连接成功之后返回的类,不能由用户实例化。

  • class httplib.HTTPMessage

HTTPMessage实例用于保存HTTP响应头。它使用mimetools.Message类实现,并提供了处理HTTP头的工具函数。它不直接实例化的用户。不能由用户实例化。

异常

  • exception httplib.HTTPException

Exception的子类,此模块中的其他异常的基类。下面的类默认是该类的直接子类。

  • httplib.NotConnected

  • httplib.InvalidURL

  • httplib.UnknownProtocol

  • httplib.UnknownTransferEncoding

  • httplib.UnimplementedFileMode

  • httplib.IncompleteRead

  • httplib.ImproperConnectionState

  • httplib.CannotSendRequest

ImproperConnectionState的一个子类。

  • httplib.CannotSendHeader

ImproperConnectionState的一个子类。

  • httplib.ResponseNotReady

ImproperConnectionState的一个子类。

  • httplib.BadStatusLine

服务器返回的HTTP状态码不认识时产生。

常量和类变量

  • httplib.HTTP_PORT:HTTP协议的默认端口,恒为80。

  • httplib.HTTPS_PORT:HTTPS协议的默认端口,恒为443。

  • 状态常量:参见http://docs.python.org/2/library/httplib.html

  • httplib.responses:映射HTTP1.1状态代码映射到W3C的名字的字典。2.5新增

1
>>> httplib.responses[httplib.NOT_FOUND] 'Not Found'

HTTPConnection类的方法

  • HTTPConnection.request(method, url[, body[, headers]])

发送请求HTTP请求到服务器,使用方法method和指定的地址url。如果有body,一般是字符串数据,将在headers之后发送。当然body也可以是支持fileno()和read()方法的文件对象,这时会发送文件内容。header内容长度会自动填充为正确的值,headers是额外HTTP头的映射,会和请求一起发送。2.6开始支持文件对象。

  • HTTPConnection.getresponse()

用于在请求发送以后从服务器端获取响应。返回HTTPResponse实例。注意发送下一条请求之前必须读完整个响应。

  • HTTPConnection.set_debuglevel(level)

设置调试级别(调试输出打印量)。默认的调试级别为0 ,表示没有调试输出打印。

  • HTTPConnection.set_tunnel(host, port=None, headers=None)

设置HTTP连接隧道的主机和端口。需要通过代理服务器做HTTPS连接时使用。header参数必须为额外HTTP头的映射随CONNECT一起发送。2.7新增。

  • HTTPConnection.connect()

对象创建之后连接到指定的服务器。

  • HTTPConnection.close()

关闭到服务器的连接。

下面四个函数可以代替request()一步步发送请求。

  • HTTPConnection.putrequest(request, selector[, skip_host[, skip_accept_encoding]])

连接到服务器后的第一个调用。它发送由request字符串,selector字符串, HTTP版本(HTTP/1.1)的行数据到服务器。设置skip_host为非Fasle值可禁用自动发送主机,设置skip_accept_encoding为非Fasle值可禁用接受编码。skip_accept_encoding为2.4添加。

  • HTTPConnection.putheader(header, argument[, ...])

发送一个RFC 822样式头到服务器。它发送由header,一个冒号和一个空格,第一个参数到服务器。如果有更多参数会发送多行,每行由一个tab和一个参数组成。

  • HTTPConnection.endheaders(message_body=None)

发送空行到服务器,指示header的结束。可选的optional message_body参数可以用来传递与请求相关的消息体。消息体如果是字符串将在消息头的包发送,如果它是字符串,否则用单独数据包。2.7加入message_body。

  • HTTPConnection.send(data)

将数据发送到服务器。endheaders()之后,getresponse()之前使用。

HTTPResponse类的方法

  • HTTPResponse.read([amt])

读取并返回response的body,或下面的amt字节。

  • HTTPResponse.getheader(name[, default])

获得头名,如果没有匹配的头返回default。

  • HTTPResponse.getheaders()

返回(header, value)元组构成的列表。2.4新增。

  • HTTPResponse.fileno()

返回底层套接字的的fileno。

  • HTTPResponse.msg

包含响应头的mimetools.Message实例。

  • HTTPResponse.version

服务器使用的HTTP协议版本。10表示HTTP/1.011表示HTTP/1.1。

  • HTTPResponse.status

由服务器返回的状态代码。

  • HTTPResponse.reason

服务器的原因短语。

实例

HTTP GET

1
2
3
#!/usr/bin/env python# -*- coding: utf-8 -*-import httplibconn = httplib.HTTPConnection("www.python.org")conn.request("GET", "/index.html")r1 = conn.getresponse()print r1.status, r1.reason#data1 = r1.read()print data1
conn.request( "GET" "/parrot.spam" )r2  =  conn.getresponse() print  r2.status, r2.reason
data2  =  r2.read() #print data2conn.close()

执行结果

1
2
3
# ./http_get.py 
200 OK
404 Not Found

HTTP HEAD

注意HEAD不会返回任何数据。

1
2
#!/usr/bin/env python# -*- coding: utf-8 -*-import httplibconn = httplib.HTTPConnection("www.python.org")conn.request("HEAD","/index.html")res = conn.getresponse()print res.status, res.reason
data  =  res.read() print  len (data) print  data  = =  ''conn.close()

执行结果

1
2
3
4
# ./http_head.py 
200 OK
0
True

HTTP POST

1
2
3
4
#!/usr/bin/env python# -*- coding: utf-8 -*-import httplib, urllibparams = urllib.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})headers = {"Content-type": "application/x-www-form-urlencoded",
     "Accept" "text/plain" }conn  =  httplib.HTTPConnection( "bugs.python.org" )conn.request( "POST" , "", params, headers)response  =  conn.getresponse() print  response.status, response.reason
data  =  response.read() print  data
conn.close()

执行结果

1
2
3
4
# ./http_head.py 
# ./test.py 
302 Found
Redirecting to  "http://bugs.python.org/issue12524" >http: //bugs .python.org /issue12524 < /a >

HTTP PUT

客户端的HTTP PUT请求和POST类似。不同之处在于服务器端允许PUT创建资源。

1
>>>  # This creates an HTTP message>>> # with the content of BODY as the enclosed representation>>> # for the resource http://localhost:8080/foobar...>>> import httplib>>> BODY = "***filecontents***">>> conn = httplib.HTTPConnection("localhost", 8080)>>> conn.request("PUT", "/file", BODY)>>> response = conn.getresponse()>>> print resp.status, response.reason200, OK


相关实例应用

客户端的HTTP PUT请求和POST类似。不同之处在于服务器端允许PUT创建资源。

1



举例1 http对象定义:
#!/usr/bin/env python
# coding: gbk

import os  
import httplib  
import socket  
import urllib
import json

class HTTPClient( object ):
    """
        http通讯协议,客户端常用方法
    """
    # Client对象属性
    host=None
    port=None
    timeout=None
    METHOD = "POST" # 默认为POST方式提交
    # http头信息
    HEADERS = { "Content-Type": "application/x-www-form-urlencoded"
    }
    # Client对象行为
    def __init__( self, host, port=8080, timeout=60):
        self.host = host
        self.port = port
        self.timeout = timeout
        
    def get_conn( self ):
        """
            获取http连接对象
        """
        conn = None
        try:
            conn = httplib.HTTPConnection( self.host, self.port, timeout=self.timeout)
            return conn
        except:
            raise
    
    def request( self, conn, url, params, method=None, headers=None):
        """
            发送请求
        """
        try:
            if not method:
                method = self.METHOD
            if not headers:
                headers = self.HEADERS
            if type( headers ) != dict:
                raise RuntimeError( "headers数据异常" )
                
            if not headers.has_key( "Content-Type" ):
                headers.update( self.HEADERS )
                
            if method == 'POST':
                ctype = headers.get( 'Content-Type' ).upper()
                if 'application/x-www-form-urlencoded'.upper() in ctype:
                    params  = urllib.urlencode( params ) # params要求是字典
                    conn.request( method, url, params, headers)
                elif 'application/json'.upper() in ctype:
                    params = json.dumps( params ) # 默认encoding utf-8
                    headers = {
                        "Content-Type" : ctype
                    }
                    conn.request( method, url, params, headers)
                elif 'text/xml'.upper() in ctype:
                    headers = {
                        "Content-Type" : ctype
                    }
                    conn.request( method, url, params, headers)
                else:
                    raise RuntimeError( "暂不支持[%s]类请求" % ctype )
            elif method == 'GET':
                params = urllib.urlencode( params )  # params要求是字典
                _url = "%s?%s" % ( url, params )
                conn.request( method, _url, None, headers )
            else:
                raise RuntimeError( "暂不支持[%s]类请求" % method )
            resp = conn.getresponse()
            return resp
        except:
            raise
        
    def close_conn( self, conn ):
        """
            关闭连接
        """
        conn.close()




def test( host ):
    import hashlib
    conn = None
    try:
        client = HTTPClient( host, port='9077' ) # 获取https客户端对象
        conn = client.get_conn() # 获取连接对象
        secret = '8d939eabe1839d3784cb28de32b0a092'
        aid    = '99990001'
        d = {
            "header":{ "version":"1.0", "method":"create"},
            "data":{
                "aid":"99990001",
                "desc":"30#啤酒500箱,立即发货".decode("gbk").encode("utf-8"),
                "logid":"13911119999",
                "amount":"000000000100",
                "localtime":"20141120201120",
                "orderid":"20150108101110",
                "callback": urllib.unquote( "https://46.17.189.110/ordernotice" )
            }
        }
        
        hash = hashlib.md5()
        
        hash.update( '%s%s%s%s' % ( secret, d['data']['orderid'], d['data']['amount'], d['data']['callback'] ) )
        d['data']['token'] = hash.hexdigest()
        url="/callback/khzf"
        
        
        # 支付订单查询
        headers = { 'Content-Type' : "text/xml"}
        d = """KHCSBTermSsn=140918000000|ETermSsn=140918112019|MercCode=983708160002901|OTranAbbr=KHZF12fec0b699ccdd97696cc855147221c418532a9ba9b6ad22be21d7f78f6ed580b22931ff6be69769e18b262e9986595c6a854825a840febf48d9e2316e2a8de722c28f035cd61ebd20ad99329e046e84f0f17d57bb0f22a83019976d7c446cfb5f7190c4365e4f078bc5933b436ac0c742824de0576cc8cb4c859f8c8452f31d"""
        resp = client.request( conn, url, d, headers=headers, method="POST" )
        
        print resp.status, resp.reason
        
    except RuntimeError, e:
        print e
    finally:
        if conn: conn.close()
        
if __name__ == '__main__':
    test( '42.96.249.190' )


举例2 https对象定义:
#!/usr/bin/env python
# coding: gbk




import os  
import httplib  
import socket  
import urllib
import json
from jnxlk_utils import str_to_dic




class HTTPSClient( object ):
    """
        https 通讯,客户端常用方法
    """
    # Client对象属性
    host=None
    port=None
    key_file=None
    cert_file=None
    timeout=None
    METHOD = "POST" # 默认为POST方式提交
    # http头信息
    HEADERS = { "Content-Type": "application/x-www-form-urlencoded"
    }
    # Client对象行为
    def __init__( self, host, port=443, key_file=None, cert_file=None, timeout=60):
        self.host = host
        self.port = port
        self.key_file = key_file
        self.cert_file = cert_file
        self.timeout = timeout
        
    def get_conn( self ):
        """
            获取http连接对象
        """
        conn = None
        try:
            conn = httplib.HTTPSConnection( self.host, self.port, self.key_file, self.cert_file, timeout=self.timeout)
            return conn
        except:
            raise
    
    def request( self, conn, url, params, method=None, headers=None):
        """
            发送请求
        """
        try:
            if not method:
                method = self.METHOD
            if not headers:
                headers = self.HEADERS
            if type( headers ) != dict:
                raise RuntimeError( "headers数据异常" )
                
            if not headers.has_key( "Content-Type" ):
                headers.update( self.HEADERS )
                
            if method == 'POST':
                ctype = headers.get( 'Content-Type' ).upper()
                if 'application/x-www-form-urlencoded'.upper() in ctype:
                    params  = urllib.urlencode( params ) # params要求是字典
                    conn.request( method, url, params, headers)
                elif 'application/json'.upper() in ctype:
                    params = json.dumps( params ) # 默认encoding utf-8
                    headers = {
                        "Content-Type" : ctype
                    }
                    conn.request( method, url, params, headers)
                elif 'text/xml'.upper() in ctype:
                    headers = {
                        "Content-Type" : ctype
                    }
                    conn.request( method, url, params, headers)
                else:
                    raise RuntimeError( "暂不支持[%s]类请求" % ctype )
            elif method == 'GET':
                params = urllib.urlencode( params )  # params要求是字典
                _url = "%s?%s" % ( url, params )
                conn.request( method, _url, None, headers )
            else:
                raise RuntimeError( "暂不支持[%s]类请求" % method )
            resp = conn.getresponse()
            return resp
        except:
            raise
        
    def close_conn( self, conn ):
        """
            关闭连接
        """
        conn.close()


举例3 http通讯应用:
# coding: gbk




import os  
import httplib  
import socket  
import urllib
from http_client import HTTPClient
from uni.apis.utils import ftp_put, ftp_get
from uni.core import logp
from shangjie.conf import settings




  
__all__ = ["SignVerify"]




class SignVerify( object ):
    
    """
        证书验证类
        url="/jnhxsdgsetcsjpay/sign"   # 无文件签名
        url1="/jnhxsdgsetcsjpay/signFile"  # 有文件签名
        url2="/jnhxsdgsetcsjpay/signcheck" # 签名验签
        url2="/jnhxsdgsetcsjpay/signcheckFile" # 有文件签名验签 
    """
    url = None
    host = None
    url = None
    def __init__( self, host, port, url=None, timeout=30 ):
        """
            创建验证类
        """
        self.host = host
        self.port = port
        self.url  = url
        self.timeout = timeout
                
    def getSignData( self, plainData, filename = None, user=None, passwd=None ):
        """
            根据原始报文数据plainData
            生成签名signData
            @filename   : 文件是否存在的标志,非空即表示有文件
            @plainData : 原始报文
            @filename  : 文件名
        """
        self.url = "/jnhxsdgsetcsjpay/sign"  # 无文件时需要访问的路径
        if filename:
            # host , port , user , passwd
            self.url = "/jnhxsdgsetcsjpay/signFile"  # 有文件时需要访问的路径
            ftp_put( self.host , 21 , user , passwd ,  os.path.join(settings.FTP_JAVA_PATH,filename) )
            logp.info( '文件传送java服务器成功' )
        method = "POST"
        conn = None
        try:
            # 获得httpsclient对象
            http_client = HTTPClient( self.host, self.port )
            
            # 连接三方
            conn = http_client.get_conn()
            
            # 构造请求字典
            headers = { # http请求头
                 'Content-Type':"application/x-www-form-urlencoded"
            }
            data = {
                "plain":plainData
            }
            response = http_client.request( conn, self.url, data, method=method, headers=headers )
            # 解析报文  返回的报文eval()一下就可以转换成字典格式  成功时:{'response':'True','return_value':'签名串'}  失败时:{'response':'False','return_value':'失败原因'}
            resp = response.read()
            ############返回的resp是字符串,需要转换成字典,注意修改他行批扣流程#############
            resp = eval( resp )
            # print '签名后的返回内容:', response.status, response.reason, resp
        except Exception, e:
            logp.info( 'java加解密服务器报错:%s'%str(e) )
            resp = {}
        finally:
            if conn : 
                conn.close()
        return resp
        
    def verSignData( self, plainData, filename=None, user=None, passwd=None  ):
        """
            根据原始报文判断签名是否正确;
            批量查询类交易、文件传输类交易这两支交易需要在验签成功后返回一个文件名;
            @ filename   : 文件是否存在的标志,非空即表示有文件
            @ plainData : 原始报文
            @ return True,filename=None or False
        """
        self.url = "/jnhxsdgsetcsjpay/signcheck"
        if filename:
            self.url = "/jnhxsdgsetcsjpay/signcheckFile"
        method = "POST"
        conn = None
        try:
            # 获得httpsclient对象
            http_client = HTTPClient( self.host, self.port )
            
            # 连接三方
            conn = http_client.get_conn()
            
            # 构造请求字典
            headers = { # http请求头
                 'Content-Type':"application/x-www-form-urlencoded"
            }
            
            data = {
                "plain":plainData
            } 
            
            response = http_client.request( conn, self.url, data, method=method, headers=headers )
            # 解析报文
            resp = response.read() # 一个字符串
            logp.info( '验签的返回内容:%s,%s,%s'%(response.status, response.reason, resp) )
            ############返回的resp是字符串,需要转换成字典,注意修改他行批扣流程#############
            resp = eval( resp )    # 转换成字典:成功时:{'response':'True','return_value':'空值','filename':'文件名'}  失败时:{'response':'False','return_value':'失败原因','filename':'空值'}
            
            if resp['filename']:
                # host , port , user , passwd
                ftp_get( self.host , 21 , user , passwd , os.path.join(settings.FTP_JAVA_PATH,resp['filename']) )
                
                logp.info( '成功从java服务模块的D:/file文件中获取到文件!' ) 
                
        except Exception, e:
            raise
            resp = {}
        finally:
            if conn : 
                conn.close()
        return resp






举例4 https通讯应用:


举例3 http通讯应用:
# coding: gbk




import os  
import httplib  
import socket  
import urllib
from http_client import HTTPClient
from uni.apis.utils import ftp_put, ftp_get
from uni.core import logp
from shangjie.conf import settings




  
__all__ = ["SignVerify"]




class SignVerify( object ):
    
    """
        证书验证类
        url="/jnhxsdgsetcsjpay/sign"   # 无文件签名
        url1="/jnhxsdgsetcsjpay/signFile"  # 有文件签名
        url2="/jnhxsdgsetcsjpay/signcheck" # 签名验签
        url2="/jnhxsdgsetcsjpay/signcheckFile" # 有文件签名验签 
    """
    url = None
    host = None
    url = None
    def __init__( self, host, port, url=None, timeout=30 ):
        """
            创建验证类
        """
        self.host = host
        self.port = port
        self.url  = url
        self.timeout = timeout
                
    def getSignData( self, plainData, filename = None, user=None, passwd=None ):
        """
            根据原始报文数据plainData
            生成签名signData
            @filename   : 文件是否存在的标志,非空即表示有文件
            @plainData : 原始报文
            @filename  : 文件名
        """
        self.url = "/jnhxsdgsetcsjpay/sign"  # 无文件时需要访问的路径
        if filename:
            # host , port , user , passwd
            self.url = "/jnhxsdgsetcsjpay/signFile"  # 有文件时需要访问的路径
            ftp_put( self.host , 21 , user , passwd ,  os.path.join(settings.FTP_JAVA_PATH,filename) )
            logp.info( '文件传送java服务器成功' )
        method = "POST"
        conn = None
        try:
            # 获得httpsclient对象
            http_client = HTTPClient( self.host, self.port )
            
            # 连接三方
            conn = http_client.get_conn()
            
            # 构造请求字典
            headers = { # http请求头
                 'Content-Type':"application/x-www-form-urlencoded"
            }
            data = {
                "plain":plainData
            }
            response = http_client.request( conn, self.url, data, method=method, headers=headers )
            # 解析报文  返回的报文eval()一下就可以转换成字典格式  成功时:{'response':'True','return_value':'签名串'}  失败时:{'response':'False','return_value':'失败原因'}
            resp = response.read()
            ############返回的resp是字符串,需要转换成字典,注意修改他行批扣流程#############
            resp = eval( resp )
            # print '签名后的返回内容:', response.status, response.reason, resp
        except Exception, e:
            logp.info( 'java加解密服务器报错:%s'%str(e) )
            resp = {}
        finally:
            if conn : 
                conn.close()
        return resp
        
    def verSignData( self, plainData, filename=None, user=None, passwd=None  ):
        """
            根据原始报文判断签名是否正确;
            批量查询类交易、文件传输类交易这两支交易需要在验签成功后返回一个文件名;
            @ filename   : 文件是否存在的标志,非空即表示有文件
            @ plainData : 原始报文
            @ return True,filename=None or False
        """
        self.url = "/jnhxsdgsetcsjpay/signcheck"
        if filename:
            self.url = "/jnhxsdgsetcsjpay/signcheckFile"
        method = "POST"
        conn = None
        try:
            # 获得httpsclient对象
            http_client = HTTPClient( self.host, self.port )
            
            # 连接三方
            conn = http_client.get_conn()
            
            # 构造请求字典
            headers = { # http请求头
                 'Content-Type':"application/x-www-form-urlencoded"
            }
            
            data = {
                "plain":plainData
            } 
            
            response = http_client.request( conn, self.url, data, method=method, headers=headers )
            # 解析报文
            resp = response.read() # 一个字符串
            logp.info( '验签的返回内容:%s,%s,%s'%(response.status, response.reason, resp) )
            ############返回的resp是字符串,需要转换成字典,注意修改他行批扣流程#############
            resp = eval( resp )    # 转换成字典:成功时:{'response':'True','return_value':'空值','filename':'文件名'}  失败时:{'response':'False','return_value':'失败原因','filename':'空值'}
            
            if resp['filename']:
                # host , port , user , passwd
                ftp_get( self.host , 21 , user , passwd , os.path.join(settings.FTP_JAVA_PATH,resp['filename']) )
                
                logp.info( '成功从java服务模块的D:/file文件中获取到文件!' ) 
                
        except Exception, e:
            raise
            resp = {}
        finally:
            if conn : 
                conn.close()
        return resp

举例3 http通讯应用:    

你可能感兴趣的:(python)