SOUNDCLOUD API:使用soundcloud-python获取错误429的响应正文

时间:2023-01-15 12:46:00

I'm using soundcloud-python https://github.com/soundcloud/soundcloud-python for Soundcloud API on Ubuntu Server 16.04.1 (installed with pip install soundcloud).

我在Ubuntu Server 16.04.1上使用soundcloud-python https://github.com/soundcloud/soundcloud-python用于Soundcloud API(使用pip install soundcloud安装)。

Soundcloud API Rate Limits official page https://developers.soundcloud.com/docs/api/rate-limits#play-requests says that, in case an app exceeds the API rate limits, the body of the 429 Client Error response would be a JSON object, containing some additional info.

Soundcloud API速率限制官方页面https://developers.soundcloud.com/docs/api/rate-limits#play-requests表示,如果应用程序超出API速率限制,429客户端错误响应的主体将是一个JSON对象,包含一些其他信息。

I'm interested in getting reset_time field, to inform the user when the block will be over.

我对获取reset_time字段感兴趣,以便在块结束时通知用户。

The problem is that when, for example, like rate limits is exceeded, doing response = client.put('/me/favorites/%d' % song_id) the app crashes and response is null.

问题是,例如,当超过速率限制时,执行response = client.put('/ me / favorites /%d'%song_id),应用程序崩溃,响应为空。

How can I get the JSON response body?

我怎样才能获得JSON响应体?

1 个解决方案

#1


0  

Why don't you read the package's source code and find out by yourself ?

你为什么不阅读包的源代码并自己找出来?

Let's see... You don't explain you got that client object but browsing the source code we can see there's a "client.py" module that defines a Client class. This class does'nt not define a put method explicitely but it defines the __getattr__ hook :

让我们看看......你没有解释你有客户端对象,但浏览源代码,我们可以看到有一个定义Client类的“client.py”模块。这个类没有明确定义put方法,但它定义了__getattr__钩子:

def __getattr__(self, name, **kwargs):
    """Translate an HTTP verb into a request method."""
    if name not in ('get', 'post', 'put', 'head', 'delete'):
        raise AttributeError
    return partial(self._request, name, **kwargs)

Ok, so Client.put(...) returns a partial object wrapping Client._request, which is a quite uselessly convoluted way to define Client.put(**kwargs) as return self._request("put", **kwargs).

好吧,所以Client.put(...)返回一个包装Client._request的部分对象,这是一个非常无用的复杂方法来定义Client.put(** kwargs)作为返回self._request(“put”,** kwargs )。

Now let's look at Client._request: it basically make a couple sanity checks, updates **kwargs and returns wrapped_resource(make_request(method, url, kwargs)).

现在让我们看看Client._request:它基本上做了一些健全性检查,更新** kwargs并返回wrapped_resource(make_request(method,url,kwargs))。

Looking up the imports at the beginning of the module, we can see that make_request comes from "request.py" and wrapped_resource from "resources.py".

查看模块开头的导入,我们可以看到make_request来自“request.py”,wrapped_resource来自“resources.py”。

You mention that doing an api call while over the rate limit "crashes the application" - I assume you mean "raises an exception" (BTW please post exceptions and tracebacks when saking about such problems) - so assuming this is handled at the lower level, let's start with request.make_request. A lot of data formatting / massaging obviously and finally the interesting part: a call to response.raise_for_status(). This is a hint that we are actually delegating to the famous python-requests package, which is actually confirmed a few lines above and in the requirements file

你提到在超过速率限制时进行api调用“崩溃了应用程序” - 我认为你的意思是“引发异常”(顺便说一下,请在发现这些问题时发布异常和回溯) - 所以假设这是在较低级别处理的,让我们从request.make_request开始。很多数据格式化/按摩显然最后是有趣的部分:对response.raise_for_status()的调用。这是一个提示,我们实际上委托着名的python-requests包,实际上确认了几行以及需求文件

If we read python-requests fine manual, we find out what raise_for_status does - it raises a requests.exceptions.HTTPError for client (4XX) and server (5XX) status codes.

如果我们阅读python-requests精细手册,我们会发现raise_for_status的作用 - 它会为客户端(4XX)和服务器(5XX)状态代码引发requests.exceptions.HTTPError。

Ok now we know what exception we have. Note that you had all those informations already in your exception and traceback, which would have saved us a lot of pain here had you posted it.

好的,现在我们知道我们有什么例外。请注意,您的异常和回溯中已经包含了所有这些信息,如果您发布它,这将为我们带来很多痛苦。

But anyway... It looks like we won't get the response content, does it ? Well, wait, we're not done yet - python-requests is a fairly well designed package, so chances are we can still rescue our response. And indeed, if we look at requests.exceptions source code, we find out that HttpError is a subclass of RequestException, and that RequestException is "Initialize(d)" with "request and response objects."

但无论如何......看起来我们不会得到回复内容,是吗?好吧,等等,我们还没有完成 - python-requests是一个设计得相当好的软件包,所以很有可能我们仍然可以挽救我们的响应。事实上,如果我们查看requests.exceptions源代码,我们会发现HttpError是RequestException的子类,而RequestException是“Initialize(d)”,带有“请求和响应对象”。

Hurray, we do have our response - in the exception. So all we have to do is catch the exception and check it's response attribute - which should contains the "additional informations".

华友世纪,我们确实有我们的回应 - 例外。所以我们要做的就是捕获异常并检查它的响应属性 - 它应该包含“附加信息”。

Now please understand that this took me more than half an hour to write, but about 7 minutes to sort out without the traceback - with the traceback it would have boiled down to a mere 2 minutes, the time to go to the requests.exceptions source code and make sure it keeped the request and response. Ok I'm cheating, I'm used to read source code and I use python-requests a lot, but still: you could have solved this by yourself in less than an hour, specially with python's interactive shell which let's you explore and test live objects in real time.

现在请理解,这花了我半个多小时的时间来编写,但大约需要7分钟来完成没有回溯的整理 - 回溯它只需要2分钟就可以了,是时候转到requests.exceptions source代码,并确保它保持请求和响应。好吧我在作弊,我习惯阅读源代码并且我经常使用python-requests,但仍然:你可以在不到一个小时的时间里自己解决这个问题,特别是python的交互式shell让你探索和测​​试实时活动对象。

#1


0  

Why don't you read the package's source code and find out by yourself ?

你为什么不阅读包的源代码并自己找出来?

Let's see... You don't explain you got that client object but browsing the source code we can see there's a "client.py" module that defines a Client class. This class does'nt not define a put method explicitely but it defines the __getattr__ hook :

让我们看看......你没有解释你有客户端对象,但浏览源代码,我们可以看到有一个定义Client类的“client.py”模块。这个类没有明确定义put方法,但它定义了__getattr__钩子:

def __getattr__(self, name, **kwargs):
    """Translate an HTTP verb into a request method."""
    if name not in ('get', 'post', 'put', 'head', 'delete'):
        raise AttributeError
    return partial(self._request, name, **kwargs)

Ok, so Client.put(...) returns a partial object wrapping Client._request, which is a quite uselessly convoluted way to define Client.put(**kwargs) as return self._request("put", **kwargs).

好吧,所以Client.put(...)返回一个包装Client._request的部分对象,这是一个非常无用的复杂方法来定义Client.put(** kwargs)作为返回self._request(“put”,** kwargs )。

Now let's look at Client._request: it basically make a couple sanity checks, updates **kwargs and returns wrapped_resource(make_request(method, url, kwargs)).

现在让我们看看Client._request:它基本上做了一些健全性检查,更新** kwargs并返回wrapped_resource(make_request(method,url,kwargs))。

Looking up the imports at the beginning of the module, we can see that make_request comes from "request.py" and wrapped_resource from "resources.py".

查看模块开头的导入,我们可以看到make_request来自“request.py”,wrapped_resource来自“resources.py”。

You mention that doing an api call while over the rate limit "crashes the application" - I assume you mean "raises an exception" (BTW please post exceptions and tracebacks when saking about such problems) - so assuming this is handled at the lower level, let's start with request.make_request. A lot of data formatting / massaging obviously and finally the interesting part: a call to response.raise_for_status(). This is a hint that we are actually delegating to the famous python-requests package, which is actually confirmed a few lines above and in the requirements file

你提到在超过速率限制时进行api调用“崩溃了应用程序” - 我认为你的意思是“引发异常”(顺便说一下,请在发现这些问题时发布异常和回溯) - 所以假设这是在较低级别处理的,让我们从request.make_request开始。很多数据格式化/按摩显然最后是有趣的部分:对response.raise_for_status()的调用。这是一个提示,我们实际上委托着名的python-requests包,实际上确认了几行以及需求文件

If we read python-requests fine manual, we find out what raise_for_status does - it raises a requests.exceptions.HTTPError for client (4XX) and server (5XX) status codes.

如果我们阅读python-requests精细手册,我们会发现raise_for_status的作用 - 它会为客户端(4XX)和服务器(5XX)状态代码引发requests.exceptions.HTTPError。

Ok now we know what exception we have. Note that you had all those informations already in your exception and traceback, which would have saved us a lot of pain here had you posted it.

好的,现在我们知道我们有什么例外。请注意,您的异常和回溯中已经包含了所有这些信息,如果您发布它,这将为我们带来很多痛苦。

But anyway... It looks like we won't get the response content, does it ? Well, wait, we're not done yet - python-requests is a fairly well designed package, so chances are we can still rescue our response. And indeed, if we look at requests.exceptions source code, we find out that HttpError is a subclass of RequestException, and that RequestException is "Initialize(d)" with "request and response objects."

但无论如何......看起来我们不会得到回复内容,是吗?好吧,等等,我们还没有完成 - python-requests是一个设计得相当好的软件包,所以很有可能我们仍然可以挽救我们的响应。事实上,如果我们查看requests.exceptions源代码,我们会发现HttpError是RequestException的子类,而RequestException是“Initialize(d)”,带有“请求和响应对象”。

Hurray, we do have our response - in the exception. So all we have to do is catch the exception and check it's response attribute - which should contains the "additional informations".

华友世纪,我们确实有我们的回应 - 例外。所以我们要做的就是捕获异常并检查它的响应属性 - 它应该包含“附加信息”。

Now please understand that this took me more than half an hour to write, but about 7 minutes to sort out without the traceback - with the traceback it would have boiled down to a mere 2 minutes, the time to go to the requests.exceptions source code and make sure it keeped the request and response. Ok I'm cheating, I'm used to read source code and I use python-requests a lot, but still: you could have solved this by yourself in less than an hour, specially with python's interactive shell which let's you explore and test live objects in real time.

现在请理解,这花了我半个多小时的时间来编写,但大约需要7分钟来完成没有回溯的整理 - 回溯它只需要2分钟就可以了,是时候转到requests.exceptions source代码,并确保它保持请求和响应。好吧我在作弊,我习惯阅读源代码并且我经常使用python-requests,但仍然:你可以在不到一个小时的时间里自己解决这个问题,特别是python的交互式shell让你探索和测​​试实时活动对象。