以前看到过一篇关于requests代码分析的文章,它是从最先版本开始的。论文笔,不及对方十之一二,论思路,十分佩服。要知道,我口口声声说看代码都是从最新代码看,收获有限。可是从初始版本看起,对本身大有裨益。做者的思路、代码的组织、技术的运用都是很值得去体会和学习的。json
先看起头的这个类api
class _Request(urllib2.Request): """Hidden wrapper around the urllib2.Request object. Allows for manual setting of HTTP methods. """ def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None): urllib2.Request.__init__( self, url, data, headers, origin_req_host, unverifiable) self.method = method def get_method(self): if self.method: return self.method return urllib2.Request.get_method(self)
能够看出,_Request是urllib2.Request的子类,这里重写了父类的get_method方法。若是有method,返回;若是没有,返回父类的get_method
在Request的send方法中能够看到其调用缓存
GET: if isinstance(self.params, dict): params = urllib.urlencode(self.params) else: params = self.params req = _Request(("%s?%s" % (self.url, params)), method=self.method) PUT: req = _Request(self.url, method='PUT') POST: req = _Request(self.url, method='POST')
# 若是设置了headers,就会把headers赋值给req.headers if self.headers: req.headers = self.headers # self._get_operner对认证作了判断,若是须要认证,则会执行如下代码 # authr = urllib2.HTTPPasswordMgrWithDefaultRealm() # # authr.add_password(None, self.url, self.auth.username, self.auth.password) # handler = urllib2.HTTPBasicAuthHandler(authr) # opener = urllib2.build_opener(handler) # return opener.open # 实质上仍是在用urllib2的open方法 opener = self._get_opener() try: # 将req对象传给open方法,发出请求 resp = opener(req) # 将结果信息赋值给response对象 self.response.status_code = resp.code self.response.headers = resp.info().dict if self.method.lower() == 'get': self.response.content = resp.read() success = True except urllib2.HTTPError, why: # 接收异常,why?why?why?,我充其量会写except urllib2.HTTPError, e。 self.response.status_code = why.code
Response、AuthObject都是类,只能这么介绍了,由于太简单了,没什么可说的app
class Response(object): """The :class:`Request` object. All :class:`Request` objects contain a :class:`Request.response <response>` attribute, which is an instance of this class. """ def __init__(self): self.content = None self.status_code = None self.headers = dict() def __repr__(self): try: repr = '<Response [%s]>' % (self.status_code) except: repr = '<Response object>' return repr class AuthObject(object): """The :class:`AuthObject` is a simple HTTP Authentication token. When given to a Requests function, it enables Basic HTTP Authentication for that Request. You can also enable Authorization for domain realms with AutoAuth. See AutoAuth for more details.s :param username: Username to authenticate with. :param password: Password for given username. """ def __init__(self, username, password): self.username = username self.password = password
关于认证的函数dom
def add_autoauth(url, authobject): global AUTOAUTHS AUTOAUTHS.append((url, authobject)) def _detect_auth(url, auth): return _get_autoauth(url) if not auth else auth def _get_autoauth(url): for (autoauth_url, auth) in AUTOAUTHS: if autoauth_url in url: return auth return None
一开始实在是没领会到add_autoauth的深意,在本版本中没有其余地方对其进行调用,后来发现以下注释:函数
>>> c_auth = requests.AuthObject('kennethreitz', 'xxxxxxx') >>> requests.add_autoauth('https://convore.com/api/', c_auth) >>> r = requests.get('https://convore.com/api/account/verify.json')
截取测试get的代码以下:学习
def get(url, params={}, headers={}, auth=None): r = Request() r.method = 'GET' r.url = url r.params = params r.headers = headers r.auth = _detect_auth(url, auth) r.send() return r.response
分析下在使用认证时的过程
实例化AuthObject对象成c_auth,并传入add_autoauth函数。这时全局变量AUTOAUTHS=[('https://convore.com/api/', c_auth)]。
在调用_detect_aut时,会比对当前的url是否在AUTOAUTHS中,若是在,就返回对应的auth。这里我感受AUTOAUTHS是缓存了请求的url和认证信息。get请求时,若是auth函数为None,并且请求的url在AUTOAUTHS中,则会使用AUTOAUTHS的auth信息。测试