AppEngine dev_appserver - urllib2.urlopen 本地主机问题 url

AppEngine dev_appserver - urllib2.urlopen issue with localhost url

更新

App Engine SDK 1.9.24 已于 2015 年 7 月 20 日发布,因此如果您仍然遇到此问题,只需通过更新即可解决此问题。有关确切问题和解决方案的解释,请参阅下面的 +jpatokal 的回答。

原问题

我有一个正在使用的应用程序,运行 在本地开发时遇到了麻烦。

我们有一些共享代码可以使用 urllib2.urlopen 检查我们应用程序的授权服务器。当我在本地开发时,我的应用程序从 AppEngine 发出请求时被 404 拒绝,但请求从终端成功。

我在端口 localhost:8000 上安装了 appengine 运行,在 localhost:8001

上安装了 auth 服务器
import urllib2

url = "http://localhost:8001/api/CheckAuthentication/?__client_id=dev&token=c7jl2y3smhzzqabhxnzrlyq5r5sdyjr8&username=amadison&__signature=6IXnj08bAnKoIBvJQUuBG8O1kBuBCWS8655s3DpBQIE="

try:
  r = urllib2.urlopen(url)
  print(r.geturl())
  print(r.read())
except urllib2.HTTPError as e:
  print("got error: {} - {}".format(e.code, e.reason))

从 AppEngine

中产生 got error: 404 - Not Found

AppEngine 似乎正在将架构、主机和端口添加到我尝试访问的 url 的 PATH 部分,因为这是我在身份验证服务器上看到的:

[02/Jul/2015 16:54:16] "GET http://localhost:8001/api/CheckAuthentication/?__client_id=dev&token=c7jl2y3smhzzqabhxnzrlyq5r5sdyjr8&username=amadison&__signature=6IXnj08bAnKoIBvJQUuBG8O1kBuBCWS8655s3DpBQIE= HTTP/1.1" 404 10146

并且从请求 header 我们可以看到整个方案以及主机和端口作为路径的一部分被传递(下面 header 部分):

 'HTTP_HOST': 'localhost:8001',
 'PATH_INFO': u'http://localhost:8001/api/CheckAuthentication/',
 'SERVER_PORT': '8001',
 'SERVER_PROTOCOL': 'HTTP/1.1',

有什么方法可以避免 AppEngine 开发服务器将此请求劫持到不同端口上的本地主机?还是我没有误解正在发生的事情?在我们的域不同的生产环境中一切正常。

在此先感谢您提供帮助,为我指明正确的方向。

这是 urlfetch_stub 实现引入的一个烦人的问题。我不确定是哪个 gcloud sdk 版本引入的。

我已经通过修补 gcloud SDK 解决了这个问题 - 直到 Google 解决了这个问题。

这意味着这个答案很快就会变得无关紧要

  1. 找到并打开urlfetch_stub.py,通常可以在~/google-cloud-sdk/platform/google_appengine/google/appengine/api/urlfetch_stub.py

  2. 找到
  3. 在第380行附近(取决于版本),找到:

full_path = urlparse.urlunsplit((protocol, host, path, query, ''))

并将其替换为:

full_path = urlparse.urlunsplit(('', '', path, query, ''))

更多信息

您假设问题是损坏的 PATH_INFO header 是正确的。这里的full_path是连接后传的

免责声明

我可能很容易用这个补丁破坏代理请求。因为我希望 google 能够修复它,所以我不会为此疯狂。

非常清楚此错误仅与本地应用程序开发相关 - 您不会在生产环境中看到此错误。

App Engine SDK 1.9.24 于 2015 年 7 月 20 日发布,因此如果您仍然遇到此问题,只需更新即可解决此问题。

下面是对发生的事情的简要说明。在 1.9.21 之前,SDK 使用相对路径格式化 URL 获取请求,如下所示:

GET /test/ HTTP/1.1
Host: 127.0.0.1:5000

在 1.9.22 中,为了更好地支持代理,这里更改为绝对路径:

GET http://127.0.0.1:5000/test/ HTTP/1.1
Host: 127.0.0.1:5000

根据 HTTP/1.1 规范,这两种格式都是完全合法的,请参阅 RFC 2616, section 5.1.2。然而,虽然该规范可以追溯到 1999 年,但显然有相当多的 HTTP 请求处理程序没有正确解析绝对形式,而是天真地将路径和主机连接在一起。

所以为了兼容性,恢复了以前的行为。 (除非您使用代理,在这种情况下,RFC 需要绝对路径。)