Google 网站管理员 API 给出响应 500:每个请求的后端错误
Google Webmaster API gives Response 500: Backend Error on every request
我自己打电话给 google API 而不是使用他们的 python 库,因为我在一个不方便的公司代理后面,它杀死了他们的库,所以我必须做都是我自己。
这很好用:
requests.get('https://www.googleapis.com/webmasters/v3/sites', params =
{'access_token':'my_access_token_here'})
另一方面,这不是:
site = https://www.my_website_from_the_above_function.com
site = urllib.parse.quote_plus(site)
def get_website_info():
url = 'https://www.googleapis.com/webmasters/v3/sites/{}/searchAnalytics/query'.format(site)
params = {
"endDate": "2017-12-10",
"startDate": "2017-12-01",
"access_token": my_access_token
}
r = requests.post(url, params = params)
return r
x = get_website_info().json()
我得到的只是这个错误代码:
{'error': {'code': 500,
'errors': [{'domain': 'global',
'message': 'Backend Error',
'reason': 'backendError'}],
'message': 'Backend Error'}}
即使使用推荐的 'Exponential backoff'
使用 googles API explorer 似乎工作正常:
另外:这似乎也给出了类似的错误:
r = requests.post(url, params = auth_params, data = json.dumps(params))
最后:
r = requests.post(url, params = auth_params, data = params)
刚给
{'error': {'code': 400,
'errors': [{'domain': 'global',
'message': 'This API does not support parsing form-encoded input.',
'reason': 'parseError'}],
'message': 'This API does not support parsing form-encoded input.'}}
我明白了!解决方案:
将传递 header 信息:
headers = {'Content-type': 'application/json',
'Authorization' : 'Bearer %s' % access_token}
并确保 json 数据被转储到一个字符串:
r = requests.post(url,data = json.dumps(params), headers = headers)
如果有人能解释我的回答背后的原因,那就太好了。
因此,您可以将 request
的内容视为文本,对吧?不仅是文本,而且接受字符数相对有限的文本。
考虑到这一点,一切都归结为如何将 "complex" 数据结构序列化为文本。我最近回答了 another question 关于 kinddddaaa 类似想法的文件。
如果你有一堆 key=value
参数,你可以使用简单的 "trick":
- Control names and values are escaped. Space characters are replaced by
+
, and then reserved characters are escaped as described in
[RFC1738], section 2.2: Non-alphanumeric characters are replaced by
%HH
, a percent sign and two hexadecimal digits representing the
ASCII code of the character. Line breaks are represented as "CR LF"
pairs (i.e., %0D%0A
).
- The control names/values are listed in the
order they appear in the document. The name is separated from the
value by
=
and name/value pairs are separated from each other by
&
.
所以这个数据:
{a="foo", b="bar baz"}
可以按照上述规范序列化为文本,如:a=foo&b=bar+baz
该序列化格式在 Content-type
请求的 header 中被标识为 application/x-www-form-urlencoded
。该请求的 header 告诉接收它的服务器 "Hey! The data that is coming in my body
is serialized following that convention that separates keys from values using the =
symbol and splits key/value pairs using &, changes whitespaces by +
... and so on"
(!) 非常重要: 这是 requests
模块在 POST
上使用的格式,除非另有说明。
另一种允许更多灵活性(例如维护基本类型或嵌套结构)的格式是 JSON。那就是Google服务器"wants"的格式,为了告诉服务器请求的body中包含的"text"遵循Json标准(或者约定),Content-Type
header 必须设置为 'application/json'
。
您的 Google 服务器在收到 request
后似乎正在检查 Content-type
header,如果不是 Json,它给了你一个 400
错误来指示“哦,我不明白这种格式......我想要 Json!”
这就是为什么您必须指定 Json header。
有一个比较两种格式的示例 here。
你也可以更清楚地看到它,因为最新版本的requests
模块可以为你做JSON解析。由于 JSON 格式变得如此普遍,您可以通过 json=
参数传递 Python 结构(例如 dict
)中提供的数据,模块将执行 json.dumps
并为您设置 header。这也允许您 "introspect" 稍微了解 body 的外观(以便更清楚地看到差异)。
看看这个:
from requests import Request
data = {
'a': 'foo-1 baz',
'b': 5,
'c': [1, 2, 3],
'd': '6'
}
req = Request('POST', 'http://foo.bar', data=data)
prepped = req.prepare()
print("Normal headers: %s" % prepped.headers)
print("Normal body: %s" % prepped.body)
req = Request('POST', 'http://foo.bar', json=data)
prepped = req.prepare()
print("Json headers: %s" % prepped.headers)
print("Json body: %s" % prepped.body)
输出:
Normal headers: {'Content-Length': '31', 'Content-Type': 'application/x-www-form-urlencoded'}
Normal body: d=6&a=foo-1+baz&c=1&c=2&c=3&b=5
Json headers: {'Content-Length': '52', 'Content-Type': 'application/json'}
Json body: b'{"d": "6", "a": "foo-1 baz", "c": [1, 2, 3], "b": 5}'
看出区别了吗? JSON 能够区分字符串 foo-1
或 6
(使用 "
),而不是 5
是整数,而 x-www-form
不能(查看表单编码如何不区分 integer 5 或 string 6)。与列表相同。通过使用字符 [
,服务器将能够判断 c
是一个列表(和整数)
我自己打电话给 google API 而不是使用他们的 python 库,因为我在一个不方便的公司代理后面,它杀死了他们的库,所以我必须做都是我自己。
这很好用:
requests.get('https://www.googleapis.com/webmasters/v3/sites', params =
{'access_token':'my_access_token_here'})
另一方面,这不是:
site = https://www.my_website_from_the_above_function.com
site = urllib.parse.quote_plus(site)
def get_website_info():
url = 'https://www.googleapis.com/webmasters/v3/sites/{}/searchAnalytics/query'.format(site)
params = {
"endDate": "2017-12-10",
"startDate": "2017-12-01",
"access_token": my_access_token
}
r = requests.post(url, params = params)
return r
x = get_website_info().json()
我得到的只是这个错误代码:
{'error': {'code': 500,
'errors': [{'domain': 'global',
'message': 'Backend Error',
'reason': 'backendError'}],
'message': 'Backend Error'}}
即使使用推荐的 'Exponential backoff'
使用 googles API explorer 似乎工作正常:
另外:这似乎也给出了类似的错误:
r = requests.post(url, params = auth_params, data = json.dumps(params))
最后:
r = requests.post(url, params = auth_params, data = params)
刚给
{'error': {'code': 400,
'errors': [{'domain': 'global',
'message': 'This API does not support parsing form-encoded input.',
'reason': 'parseError'}],
'message': 'This API does not support parsing form-encoded input.'}}
我明白了!解决方案:
将传递 header 信息:
headers = {'Content-type': 'application/json',
'Authorization' : 'Bearer %s' % access_token}
并确保 json 数据被转储到一个字符串:
r = requests.post(url,data = json.dumps(params), headers = headers)
如果有人能解释我的回答背后的原因,那就太好了。
因此,您可以将 request
的内容视为文本,对吧?不仅是文本,而且接受字符数相对有限的文本。
考虑到这一点,一切都归结为如何将 "complex" 数据结构序列化为文本。我最近回答了 another question 关于 kinddddaaa 类似想法的文件。
如果你有一堆 key=value
参数,你可以使用简单的 "trick":
- Control names and values are escaped. Space characters are replaced by
+
, and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by%HH
, a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as"CR LF"
pairs (i.e.,%0D%0A
).- The control names/values are listed in the order they appear in the document. The name is separated from the value by
=
and name/value pairs are separated from each other by&
.
所以这个数据:
{a="foo", b="bar baz"}
可以按照上述规范序列化为文本,如:a=foo&b=bar+baz
该序列化格式在 Content-type
请求的 header 中被标识为 application/x-www-form-urlencoded
。该请求的 header 告诉接收它的服务器 "Hey! The data that is coming in my body
is serialized following that convention that separates keys from values using the =
symbol and splits key/value pairs using &, changes whitespaces by +
... and so on"
(!) 非常重要: 这是 requests
模块在 POST
上使用的格式,除非另有说明。
另一种允许更多灵活性(例如维护基本类型或嵌套结构)的格式是 JSON。那就是Google服务器"wants"的格式,为了告诉服务器请求的body中包含的"text"遵循Json标准(或者约定),Content-Type
header 必须设置为 'application/json'
。
您的 Google 服务器在收到 request
后似乎正在检查 Content-type
header,如果不是 Json,它给了你一个 400
错误来指示“哦,我不明白这种格式......我想要 Json!”
这就是为什么您必须指定 Json header。
有一个比较两种格式的示例 here。
你也可以更清楚地看到它,因为最新版本的requests
模块可以为你做JSON解析。由于 JSON 格式变得如此普遍,您可以通过 json=
参数传递 Python 结构(例如 dict
)中提供的数据,模块将执行 json.dumps
并为您设置 header。这也允许您 "introspect" 稍微了解 body 的外观(以便更清楚地看到差异)。
看看这个:
from requests import Request
data = {
'a': 'foo-1 baz',
'b': 5,
'c': [1, 2, 3],
'd': '6'
}
req = Request('POST', 'http://foo.bar', data=data)
prepped = req.prepare()
print("Normal headers: %s" % prepped.headers)
print("Normal body: %s" % prepped.body)
req = Request('POST', 'http://foo.bar', json=data)
prepped = req.prepare()
print("Json headers: %s" % prepped.headers)
print("Json body: %s" % prepped.body)
输出:
Normal headers: {'Content-Length': '31', 'Content-Type': 'application/x-www-form-urlencoded'}
Normal body: d=6&a=foo-1+baz&c=1&c=2&c=3&b=5
Json headers: {'Content-Length': '52', 'Content-Type': 'application/json'}
Json body: b'{"d": "6", "a": "foo-1 baz", "c": [1, 2, 3], "b": 5}'
看出区别了吗? JSON 能够区分字符串 foo-1
或 6
(使用 "
),而不是 5
是整数,而 x-www-form
不能(查看表单编码如何不区分 integer 5 或 string 6)。与列表相同。通过使用字符 [
,服务器将能够判断 c
是一个列表(和整数)