python请求的URL规则

python请求的URL规则,python,python-requests,Python,Python Requests,最近,我将客户端上载代码从HTTPConnection移植到请求。上载图像时: file_name ='/path/to/216169_1286900924tait.jpg?pt=5&ek=1' 存储在磁盘上的映像实际上就是名称,我想用相同的路径和名称将其上载到远程服务器,因此我构建了如下请求: url = 'http://host/bucket_name/%s' % (file_name) headers = {...} # some other headers with open(

最近,我将客户端上载代码从
HTTPConnection
移植到
请求
。上载图像时:

file_name ='/path/to/216169_1286900924tait.jpg?pt=5&ek=1'
存储在磁盘上的映像实际上就是名称,我想用相同的路径和名称将其上载到远程服务器,因此我构建了如下请求:

url = 'http://host/bucket_name/%s' % (file_name)
headers = {...} # some other headers
with open(file_name, 'rb') as fd:
    data = fd.read()
    r = requests.put(url, data=data, headers=headers)
    assert(r.status_code==200)
    ....
但发送到服务器的请求更改为:

/path/to/216169_1286900924tait.jpg
请求
应该将尾部编码为
%3Fpt%3D5%26ek%3D1
,但似乎
请求
url
的url编码没有任何作用,我认为它可能会将
?pt=5&ek=1
模式与请求参数匹配,如何使
请求
在没有模式匹配的情况下盲目转换url

更新:
服务器获取修剪后的url并使用它计算签名,因此与我计算的签名不匹配,所以403返回

您可能在构建URL时遇到问题:

>>> payload = {'pt': 5, 'ek': '1'}
>>> r = requests.get('http://host/bucket_name/file_name', params=payload)

如果您调用print(r.url),您应该拥有正确的表单。

为什么
请求
应该假定对查询参数进行编码?它不知道您不希望URL的这一部分被视为查询字符串。此外,请求会按原样发送到服务器,查询字符串不会像您建议的那样被省略。您可以使用
nc
验证:

# run nc server
$ nc -l 1234

# then send request from Python
>>> requests.put('http://localhost:1234/path/to/216169_1286900924tait.jpg?pt=5&ek=1', data='any old thing')
nc
将显示请求:

PUT /path/to/216169_1286900924tait.jpg?pt=5&ek=1 HTTP/1.1 Host: localhost:1234 Content-Length: 13 User-Agent: python-requests/2.9.1 Connection: keep-alive Accept: */* Accept-Encoding: gzip, deflate any old thing 生成此请求:

PUT /path/to/216169_1286900924tait.jpg?pt=5&ek=1 HTTP/1.1 Host: localhost:1234 Accept-Encoding: identity Content-Length: 18 hello from httplib PUT/path/to/216169_1286900924tait.jpg?pt=5&ek=1http/1.1 主机:localhost:1234 接受编码:标识 内容长度:18 您好,来自httplib
请注意,URL的发送方式没有区别。

我深入研究了
请求
源代码,找到了以下代码行(是的,
请求
基于
urllib3
):

在构建url字符串时,您应该手动对url进行url编码,例如:

>>> path = '''~!@#$^&*()_+|}{":?><`-=\\][\';.,'''
>>> url = 'http://host.com/bucket/%s' % path
>>> urllib3.util.parse_url(url)
>>> Url(scheme='http', auth=None, host='host.com', port=None, path='/bucket/~!@', query=None, fragment='$^&*()_+|}{":?><`-=B%7C%7D%7B%22%3A%3F%3E%3C%60-%3D%5C%5D%5B%27%3B.%2C')

这就是我想要的。但是,如果要将tome unicode字符传递到
路径
,则不需要对它们进行编码,它们会自动转换为
%xx%xx
格式。但是url编码对于您传入url的任何字符都是一个很好的建议。

我不确定我是否理解“对url编码不做任何事情”或您所说的“模式匹配”是什么意思。您为
文件名
分配内容的行不能是有效的Python,因为没有引号。您的文件是否真的保存在磁盘上,文件名中有查询参数?我不确定所有的文件系统都允许这些字符。你的更新提到了一个签名,但我不知道这意味着什么。路径不同,因为有一个
表示URL的其余部分是一个签名。在您的示例中,这两个URL实际上是不同的。我认为
quote()
URL的查询部分是可以的,但是
#
很重要。顺便问一下:您是如何使用
HTTPConnection
的?您是否
quote()
查询字符串?
scheme, auth, host, port, path, query, fragment = urllib3.util.parse_url(url)
>>> path = '''~!@#$^&*()_+|}{":?><`-=\\][\';.,'''
>>> url = 'http://host.com/bucket/%s' % path
>>> urllib3.util.parse_url(url)
>>> Url(scheme='http', auth=None, host='host.com', port=None, path='/bucket/~!@', query=None, fragment='$^&*()_+|}{":?><`-=B%7C%7D%7B%22%3A%3F%3E%3C%60-%3D%5C%5D%5B%27%3B.%2C')
>>> path = '''~!@#$^&*()_+|}{":?><`-=\\][\';.,'''
>>> url = 'http://host.com/bucket/%s' % (urllib.quote(path, ''))
>>> print url
>>> http://host.com/bucket/%7E%21%40%23%24%25%5E%26%2A%28%29_%2B%7C%7D%7B%22%3A%3F%3E%3C%60-%3D%5C%5D%5B%27%3B.%2C
>>> urllib3.util.parse_url(url)
>>> Url(scheme='http', auth=None, host='host.com', port=None, path='/bucket/%7E%21%40%23%24%25%5E%26%2A%28%29_%2B%7C%7D%7B%22%3A%3F%3E%3C%60-%3D%5C%5D%5B%27%3B.%2C', query=None, fragment=None)