10

更新

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

原始问题

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

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

我在端口上运行 appengine localhost:8000,并且在身份验证服务器上运行localhost:8001

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))

这导致got error: 404 - Not Found来自 AppEngine

看来 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

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

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

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

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

4

2 回答 2

4

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

我已经通过修补 gcloud SDK 解决了这个问题——直到谷歌这样做。

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

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

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

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

并将其替换为:

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

更多信息

您假设问题是损坏的 PATH_INFO 标头是正确的。建立full_path连接后将传递此处。

免责声明

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

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

于 2015-07-07T02:05:00.573 回答
1

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,第 5.1.2 节。然而,虽然该规范可以追溯到 1999 年,但显然有相当多的 HTTP 请求处理程序没有正确解析绝对形式,而只是天真地将路径和主机连接在一起。

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

于 2015-07-21T05:33:26.660 回答