有段代码这么写的:
def http_request(request_url="", method="POST", data=""):
headers = {};
headers["Content-Type"] = "application/json;charset=utf-8";
headers["Accept"] = "application/json";
try:
# TODO: never use system default block request, use eventlet instead.
req = urllib2.Request(url=request_url, data=data, headers=headers);
req.get_method = lambda: method;
urllib2.socket.setdefaulttimeout(Constants.JOIN_TRANSCODER_TIMEOUT);
response = urllib2.urlopen(req);
except Exception, ex:
# TODO: always this error code?
code = Errors.join_transcoder_error;
msg = "url=%s connection error, code=%#x, detail=%s"%(request_url, code, ex);
Logger.error(tag, "http_request+error %s"%(msg));
return (code, msg, Errors.parse_msg(code, msg));
if not Constants.is_request_ok(response.code):
code = Errors.join_transcoder_error;
msg = "url=%s request error, code=%#x"%(request_url, code);
Logger.error(tag, "http_request+error %s"%(msg));
return (code, msg, Errors.parse_msg(code, msg));
response_str = response.read();
ret = json.loads(response_str);
return (ret["code"], "url=%s request success"%(request_url), response_str);
做的事情很少,但是看起来超级复杂,原因在于这个函数提供了:
1. http请求的功能,包括GET/POST。
2. 错误处理:错误和具体的逻辑相关(join_transcoder_error)。
3. 混乱的错误逻辑:几个地方都判断错误,返回不同的码。
4. 混乱的返回值:试图提供直接返回给client的错误信息,应该返回定义良好的错误码。
5. 实际上这个函数只是返回了http的结果,外面还得去解析json。
会导致使用起来很奇怪:
def join(self):
(code, msg, response_str) = http_request(self.worker_url, "GET", data=None);
self.error_code = code;
if not Errors.is_success(code):
self.reset(code);
return code;
ret = json.loads(response_str);
if Constants.is_offline(ret["data"]["heartbeat_time"]):
code = Errors.not_heartbeat_error;
Logger.debug(self.__tag, "transcoder+join transcoder worker_id=%s, url=%s "
"change status to offline. code=%#x"%(self.worker_id, self.worker_url, code));
self.reset(code);
return code;
self.status = ret["data"]["status"];
self.error_code = ret["code"];
self.remain_cpu = ret["data"]["remain_cpu"];
self.heartbeat_time = ret["data"]["heartbeat_time"];
if ret["data"]["remain_cpu"] == 0:
self.status = Constants.WORKER_STATUS_WORKING;
return Errors.success;
拿到http_request之后还需要解析json,很罗嗦。
建议refine如下:
'''
perform a http get request, parse the response to json.
@param url: a str indicates the url to request.
@return tuple(code, desc, data) where:
code: the error code, @see: Errors.
desc: the error description str.
data: parsed response object in json. None if error.
'''
def http_get(url):
(code, desc, data) = (Errors.success, "success", None);
try:
res = eventlet.green.urllib2.urlopen(url=str(url)).read();
except Exception, ex:
code = Errors.network_http_get;
desc = "http get error, url=%s, code=%#x, exception=%s"%(url, code, ex);
Logger.error(tag, "http_request+error %s"%(desc));
return (code, desc, data);
try:
data = json.loads(res);
except Exception, ex:
code = Errors.network_json_parse;
desc = "parse json error, url=%s, code=%#x, res=%s, exception=%s"%(url, code, res, ex);
Logger.error(tag, "http_request+error %s"%(desc));
return (code, desc, data);
return (code, desc, data);
这个函数分开了GET和POST,对结果解析为JSON。调用如下:
def join(self):
(code, desc, data) = bravo_utility.http_get(self.worker_url);
self.error_code = code;
if not Errors.is_success(code):
self.reset(code);
return code;
self.status = data["data"]["status"];
self.error_code = data["code"];
self.remain_cpu = data["data"]["remain_cpu"];
self.heartbeat_time = data["data"]["heartbeat_time"];
if data["data"]["remain_cpu"] == 0:
self.status = Constants.WORKER_STATUS_WORKING;
return Errors.success;
当然,还有更好的做法,但这样改已经有所进步了。