以前看到過一篇關於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信息。測試