为什么 Python 的 urllib.request.urlopen 发送 POST 数据作为查询字符串?
Why does Python's urllib.request.urlopen send POST data as query string?
curl
正确地将数据发布到 Solr:
$ curl -v 'http://solr.example.no:12699/solr/my_coll/update?commit=true' \
--data '<add><doc><field name="key">KEY__9927.1</field><field name="value">\
{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>'
solr 查询日志说:
[20200306T111354,131] [my_coll_shard1_replica_n85] webapp=/solr path=/update params={commit=true} status=0 QTime=96
我正在尝试用 Python 做同样的事情:
>>> import urllib.request
>>> data = '<add><doc><field name="key">KEY__9927.1</field><field name="value">{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>'
>>> url = 'http://solr.example.no:12699/solr/my_coll/update?commit=true'
>>> req = urllib.request.Request(url=url, data=data.encode('utf-8'), method='POST')
>>> res = urllib.request.urlopen(req)
但现在 solr 查询日志显示 POST 数据已添加到查询参数字符串中:
[20200306T112358,780] [my_coll_shard1_replica_n87] webapp=/solr path=/update params={commit=true&<add><doc><field+name="key">KEY__9927.1</field><field+name%3D"value">{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>} status=0 QTime=30
这里发生了什么?
问题是您没有为您的请求发送正确的 Content-Type,这在转发到日志之前在 Jetty(或 Solr 应用程序)中被破坏(任何非多部分的 POSTed 数据都可以作为查询字符串的一部分插入 - Solr 以相同的方式解析它们)。 /update
端点接受多种格式,例如 JSON 和 XML,并且应适当设置 Content-Type。
req = urllib.request.Request(url=url, data=data.encode('utf-8'), method='POST', headers={'Content-Type': 'text/xml'})
res = urllib.request.urlopen(req)
事实上,改变行为的是 User-Agent
字符串。这是设计使然 - curl
已被特殊处理以覆盖默认的 Content-Type
处理程序。如果您不使用 curl
,则必须明确提供要提交的 Content-Type
。这样做可能是为了更容易在命令行上使用 curl
进行手动请求。该实现在 SolrRequestParsers.java, line 782
中可用
curl
正确地将数据发布到 Solr:
$ curl -v 'http://solr.example.no:12699/solr/my_coll/update?commit=true' \
--data '<add><doc><field name="key">KEY__9927.1</field><field name="value">\
{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>'
solr 查询日志说:
[20200306T111354,131] [my_coll_shard1_replica_n85] webapp=/solr path=/update params={commit=true} status=0 QTime=96
我正在尝试用 Python 做同样的事情:
>>> import urllib.request
>>> data = '<add><doc><field name="key">KEY__9927.1</field><field name="value">{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>'
>>> url = 'http://solr.example.no:12699/solr/my_coll/update?commit=true'
>>> req = urllib.request.Request(url=url, data=data.encode('utf-8'), method='POST')
>>> res = urllib.request.urlopen(req)
但现在 solr 查询日志显示 POST 数据已添加到查询参数字符串中:
[20200306T112358,780] [my_coll_shard1_replica_n87] webapp=/solr path=/update params={commit=true&<add><doc><field+name="key">KEY__9927.1</field><field+name%3D"value">{"result":0,"jobId":"9459695","jobNumber":"9927.1"}</field></doc></add>} status=0 QTime=30
这里发生了什么?
问题是您没有为您的请求发送正确的 Content-Type,这在转发到日志之前在 Jetty(或 Solr 应用程序)中被破坏(任何非多部分的 POSTed 数据都可以作为查询字符串的一部分插入 - Solr 以相同的方式解析它们)。 /update
端点接受多种格式,例如 JSON 和 XML,并且应适当设置 Content-Type。
req = urllib.request.Request(url=url, data=data.encode('utf-8'), method='POST', headers={'Content-Type': 'text/xml'})
res = urllib.request.urlopen(req)
事实上,改变行为的是 User-Agent
字符串。这是设计使然 - curl
已被特殊处理以覆盖默认的 Content-Type
处理程序。如果您不使用 curl
,则必须明确提供要提交的 Content-Type
。这样做可能是为了更容易在命令行上使用 curl
进行手动请求。该实现在 SolrRequestParsers.java, line 782