改造的原因主要是因为GFW的存在,导致无法顺畅的上传代码。通过环境变量的方式添加代理又略显麻烦,且在PyCharm中无法使用。

既然是改造,那肯定要修改SDK的源代码了。目前从简单考虑,只支持HTTP代理,以GoAgent为例。而且考虑到GoAgent的代理方式会造成证书不匹配的问题(因为SDK中用到的库都不支持SNI),所以同时要禁用SSL的证书验证。

在google_appengine/google/appengine/tools/appengine_rpc.py文件中,HttpRpcServer类的_GetOpener方法

opener.add_handler(fancy_urllib.FancyProxyHandler())

修改为

proxy = "127.0.0.1:8087"
opener.add_handler(fancy_urllib.FancyProxyHandler({"http": proxy, "https": proxy}))

在google_appengine/google/appengine/tools/appengine_rpc_httplib2.py文件中,HttpRpcServerHttpLib2类的Send方法

self.http = httplib2.Http(cache=self.memory_cache, ca_certs=self.certpath)

修改为(不使用GoAgent的话,disable_ssl_certificate_validation=True这个可以不写以保证安全性)

self.http = httplib2.Http(cache=self.memory_cache, ca_certs=self.certpath, proxy_info=httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, "127.0.0.1", 8087), disable_ssl_certificate_validation=True)

在google_appengine/lib/fancy_urllib/fancy_urllib/__init__.py文件中,create_fancy_connection函数的PresetProxyHTTPSConnection类的connect方法

if self.cert_reqs & ssl.CERT_REQUIRED:

修改为(为GoAgent禁用证书校验,不使用GoAgent的可以不改这里保证安全性

if False:

到这里并没有修改完。由于在google_appengine/lib/google-api-python-client/oauth2client/client.py文件的OAuth2Credentials类的from_json方法中调用了simplejson.loads(s),然后把其中的data[‘token_uri’]传递到了httplib2中。simplejson.loads产生的字符串是unicode而非string,而google_appengine/lib/httplib2/httplib2/socks.py文件的socksocket类的connect方法判断如果不是string,就抛出GeneralProxyError,于是会导致程序异常。

考虑到这里其实应该是socks.py考虑不周,所以把socks.py文件的socksocket类的connect方法中的

(type(destpair[0]) != type(''))

修改为

(not isinstance(destpair[0], basestring))

2012-11-8 23:28 更新:神奇的,以上bug,在SDK 1.7.3版本中已经修复……

这样就可以通过代理来让appcfg.py访问GAE了。

另外appcfg.py有个–oauth2的选项,可以不输入密码,而是通过oauth2的方式获取代码上传授权,对于开了二步验证的同学会很方便,但这个不是默认开启的,每次都输入也很麻烦。

在google_appengine/google/appengine/tools/appcfg.py文件中,AppCfgApp类的_GetOptionParser方法

parser.add_option(’–oauth2’, action='store_true’, dest='oauth2’,
default=False,
help='Use OAuth2 instead of password auth.’)

把False修改为True即可。

但这样的话,PyCharm中通过用户名和密码的方式就不是很方便了,所以在后面还要加个判断,如果命令行选项里提供了邮箱,就不使用oauth2方式。

同一个文件,AppCfgApp类的_GetRpcServer方法

if self.options.oauth2 and not dev_appserver:

修改为

if not self.options.email and self.options.oauth2 and not dev_appserver:

这样就不冲突了。

这个改造并不是官方支持的,所以其中socks的代码bug也就不好上报issue到Google Code,但PyCharm的oauth2支持改进是可以提的,而且鉴于我之前给PyCharm报的数个issue都得到了良好的处理,也希望这个能在设计得到改善2012-11-21 Update:122.878中已经修复。