如何在 google 应用引擎 (python) 上获得流式传输 url 的响应

How to get a response for a streaming url on google app engine (python)

我正在尝试验证在线广播 url 是否正在传送音乐以及 url 是否被重定向(如果出于某种原因请求 url 错误,则会发生这种情况或不活跃)。我在这里 Fetching url in python with google app engine 找到了一些建议。但是,对于提供 Content-Type:audio/mpeg 的 url,它似乎不起作用。

在我的本地机器上使用 python 2.7.6 urllib2.urlopen 一切正常:

try:
    print "begin urlopen"
    url = urllib2.urlopen("http://streaming.radionomy.com/jamaican-roots-radio")
    print "end urlopen"

except Exception, e:
    print e

给予

begin urlopen

end urlopen

我可以从 returned object(这是一个 socket._fileobject)中读取 N 个字节并使用方法 geturl( ) 以获取流来自的实际 url(如果没有重定向,则请求 url 和检索到的资源 url 相同)

将 dev_appserver.py 用于 google appengine 时会出现问题(我还没有部署)。调用从不 returns:

begin urlopen

WARNING 2015-06-12 14:31:43,599 urlfetch_stub.py:504] Stripped prohibited headers from URLFetch request: ['Host']

和 "end urlopen" 永远不会打印。

我理解警告错误,所以我切换(按照上面 link 中的建议)到 urlfetch:

try:
    print "begin fetch"
    url = urlfetch.fetch("http://streaming.radionomy.com/jamaican-roots-radio")
    print "end fetch"

except Exception, e:
    print e

给予

begin

警告消失了,但调用也没有 return。

对于一个普通的网页url,一切都符合预期。我猜问题出在从未完成的响应 object 上。同时使用

urlfetch.set_default_fetch_deadline(5)

没有改变这种情况,可能是因为数据是从服务器连续流式传输的(因此没有调用超时??)。 我也尝试了低级别 httplib.HTTPConnection,但是在发出请求后 getresponse() 函数永远不会 returns。

就我的目的而言,回复 header 就足够了。但是在服务器上(不在我的控制之下)HEAD 方法没有实现(尽管在 Access-Control-Allow-Methods 中列出,因为它可以从浏览器中看到)

curl -X HEAD -i http://streaming.radionomy.com/jamaican-roots-radio

HTTP/1.0 501 Not Implemented

我没有在 Whosebug 上找到任何关于流 url 的问题,除了这个 。不幸的是,建议的回复对我不是很有帮助 ("Using Twitter's 'standard' API")。

我能解决这个问题吗?

更新

在 google appengine 上(不是在上面的 dev_appserver.py 上)问题是相似的:

Deadline exceeded while waiting for HTTP response from URL...

Traceback (most recent call last):

File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 267, in Handle result = handler(dict(self._environ), self._StartResponse)

File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.3/webapp2.py", line 1505, in call rv = self.router.dispatch(request, response)

File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.3/webapp2.py", line 1253, in default_dispatcher return route.handler_adapter(request, response)

File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.3/webapp2.py", line 1077, in call return handler.dispatch()

File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.3/webapp2.py", line 545, in dispatch return method(*args, **kwargs)

File "/base/data/home/apps/s~radiosnoozers/3.384985169499124712/controllers/checkurl.py", line 80, in get print e

File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/request_environment.py", line 94, in write self._request.errors.write(data)

File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/logservice/logservice.py", line 287, in write self._write(line)

File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/logservice/logservice.py", line 307, in _write if self._request != logsutil.RequestID():

DeadlineExceededError

遵守超时,使用 allow_truncated=True 没有区别。无论如何,无法访问响应...

我真的不知道发生了什么,但感谢您的建议。

如果 URL 是基于 HTTP 的流端点,则可能是使用 http 范围请求完成的。这意味着,如果您只想获取流的特定字节范围(比如前几个字节),则需要告诉 urlfetch 这样做。您可以通过指定 request headers for urlfetch 并指定字节范围(例如 headers={'Range': 'bytes=0-299'})

UrlFetch 用于从 URL 中获取有限资源,并且通常不能很好地处理流。它正在等待请求终止。我相信端点一般不能很好地处理 Range 请求。当我的浏览器点击该流时,请查看 headers(顺便说一句,很棒的流):

GET http://streaming.radionomy.com/jamaican-roots-radio HTTP/1.1
Host: streaming.radionomy.com
Proxy-Connection: keep-alive
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36
Accept: */*
Referer: http://streaming.radionomy.com/jamaican-roots-radio
Accept-Language: en-US,en;q=0.8
Cookie: gsScrollPos=
Range: bytes=0-

现在看看回复:

HTTP/1.1 200 OK
Accept-Ranges: none
icy-br: 128
ice-audio-info: bitrate=128;samplerate=44100;channels=2
icy-br: 128
icy-description: Radio Online producida en Colombia.  Al aire: Ska Reggae Rocksteady jamaiquino las 24 horas los 7 días a la semana. http://www.jamaicanroots.com.co/
icy-genre: Jamaican
icy-name: JamaicanRootsRadio
icy-pub: 1
icy-url: http://www.jamaicanroots.com.co
Server: Icecast 2.3.3-kh8
Cache-Control: no-cache, no-store
Pragma: no-cache
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type
Access-Control-Allow-Methods: GET, OPTIONS, HEAD
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Transfer-Encoding: chunked
Content-Type: audio/mpeg
Date: Wed, 17 Jun 2015 19:35:42 GMT
Via: **[my proxy here]**
Connection: keep-alive
Proxy-Connection: keep-alive

事实上,正如我上面所暗示的,我认为流本身不能很好地与 HTTP 兼容。如果您尝试 运行 通过 CURL 的等效请求并指定 Range: bytes=0-100,您会注意到范围请求 header 未得到遵守,它会流式传输永远。

因此,您似乎需要使用 Managed VM or Compute Engine 实例来手动打开和关闭连接。