如何在 xmlrpc 中,使用带密码的 http 代理

#问题:
希望将局域网内的电脑作为客户端(此电脑需要通过代理服务器访问外网),代理服务器需要用户名及密码,访问互联网上一服务器中的xmlrpc服务

#代码
以下是官方参考文档中的代码,问题是再用http.client.HTTPConnection()连接需要账户的代理服务器时,如何设置用户名、密码?

import http.client
import xmlrpc.client
class ProxiedTransport(xmlrpc.client.Transport):
 def set_proxy(self, host, port=None, headers=None): 
    self.proxy = host, port
    self.proxy_headers = headers

def make_connection(self, host):
#此处如何设置代理服务器的用户名和密码?
connection = http.client.HTTPConnection(*self.proxy) 

   connection.set_tunnel(host, headers=self.proxy_headers) 
   self._connection =  host, connection
   return connection

transport = ProxiedTransport()
transport.set_proxy('proxy-server', 8080)
server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport)

print(server.examples.getStateName(41))
最佳答案

终于搞定,用了个曲线救国的办法:
1.我发现用urllib.ProxyHandler可以很容易通过代理服务器访问远程http、XMLRPC服务器,包括需要密码的代理服务器。
2.研究了一下python自带的xmlrpc包中的代码,发现建立连接时,主要靠xmlrpc.client.Transport下的single_request()方法来返回response中的内容
3.由于ServerProxy(url, transport=transport)中,可以传入自定义的Transport子类,来控制用代理服务器连接,故重写了single_request方法(不需要再重写官方文档中提到的make_connection()),将其中的以下代码:

http_conn = self.send_request(host, handler, request_body, verbose)
resp = http_conn.getresponse()

改为了:

proxy = urllib.request.ProxyHandler({"http":"http://{}:{}@{}:{}".format(USERNAME,PASSWORD,PROXY_IP,PROXY_PORT)})
opener = urllib.request.build_opener(proxy)
resp = opener.open(url,request_body)

成功通过。
我觉得这个功能意义挺大的,可以彻底打穿局域网,公司内的电脑只要能上外网,就可通过xmlrpc被完全访问。我所在公司的电脑是全部加了AD域的,需要用AD域 的用户名密码登录代理服务器,用此法完美打穿。
附完整代码:

USERNAME = '***'
PASSWORD = '***'
PROXY_IP = '***'
PROXY_PORT = '***'
class ProxiedTransport(Transport):
    def set_proxy(self, host, port=None, headers=None): 
        self.proxy = host, port
        self.proxy_headers = headers

    def single_request(self,host,handler,request_body,verbose=False):
        try:
            proxy = urllib.request.ProxyHandler({"http":"http://{}:{}@{}:{}".format(USERNAME,PASSWORD,*self.proxy)})
            opener = urllib.request.build_opener(proxy)
            resp = opener.open(url,request_body)
            if resp.status == 200:
                self.verbose = verbose
                return self.parse_response(resp)
        except Fault:
                raise
        except Exception:
                self.close()
                raise
        #We got an error response.
        #Discard any response data and raise exception
        if resp.getheader("content-length", ""):
            resp.read()
        raise ProtocolError(
            host + handler,
            resp.status, resp.reason,
            dict(resp.getheaders())
            )


transport = ProxiedTransport()

url = 'http://XX.XX.XX.XX:XXXX/RPC2'
transport.set_proxy(PROXY_IP,PROXY_PORT)
server = ServerProxy(url, transport=transport)

try:
    pass
    print(server.getClient("server"))
except Exception as e:
    print("e:",e)
4年前 评论
讨论数量: 2
Jason990420

Try this

from base64 import b64encode

auth = str.encode("%s:%s" % (username, password))
user_and_pass = b64encode(auth).decode("ascii")
headers = {'Authorization': 'Basic %s' % user_and_pass, "Accept": 'application/json'}
4年前 评论
JoshuaWeiss (楼主) 4年前

终于搞定,用了个曲线救国的办法:
1.我发现用urllib.ProxyHandler可以很容易通过代理服务器访问远程http、XMLRPC服务器,包括需要密码的代理服务器。
2.研究了一下python自带的xmlrpc包中的代码,发现建立连接时,主要靠xmlrpc.client.Transport下的single_request()方法来返回response中的内容
3.由于ServerProxy(url, transport=transport)中,可以传入自定义的Transport子类,来控制用代理服务器连接,故重写了single_request方法(不需要再重写官方文档中提到的make_connection()),将其中的以下代码:

http_conn = self.send_request(host, handler, request_body, verbose)
resp = http_conn.getresponse()

改为了:

proxy = urllib.request.ProxyHandler({"http":"http://{}:{}@{}:{}".format(USERNAME,PASSWORD,PROXY_IP,PROXY_PORT)})
opener = urllib.request.build_opener(proxy)
resp = opener.open(url,request_body)

成功通过。
我觉得这个功能意义挺大的,可以彻底打穿局域网,公司内的电脑只要能上外网,就可通过xmlrpc被完全访问。我所在公司的电脑是全部加了AD域的,需要用AD域 的用户名密码登录代理服务器,用此法完美打穿。
附完整代码:

USERNAME = '***'
PASSWORD = '***'
PROXY_IP = '***'
PROXY_PORT = '***'
class ProxiedTransport(Transport):
    def set_proxy(self, host, port=None, headers=None): 
        self.proxy = host, port
        self.proxy_headers = headers

    def single_request(self,host,handler,request_body,verbose=False):
        try:
            proxy = urllib.request.ProxyHandler({"http":"http://{}:{}@{}:{}".format(USERNAME,PASSWORD,*self.proxy)})
            opener = urllib.request.build_opener(proxy)
            resp = opener.open(url,request_body)
            if resp.status == 200:
                self.verbose = verbose
                return self.parse_response(resp)
        except Fault:
                raise
        except Exception:
                self.close()
                raise
        #We got an error response.
        #Discard any response data and raise exception
        if resp.getheader("content-length", ""):
            resp.read()
        raise ProtocolError(
            host + handler,
            resp.status, resp.reason,
            dict(resp.getheaders())
            )


transport = ProxiedTransport()

url = 'http://XX.XX.XX.XX:XXXX/RPC2'
transport.set_proxy(PROXY_IP,PROXY_PORT)
server = ServerProxy(url, transport=transport)

try:
    pass
    print(server.getClient("server"))
except Exception as e:
    print("e:",e)
4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!