在没有 SSL 证书验证的情况下使用 urllib 发布数据
Posting data using urllib without SSL certificate validation
我需要 post 数据到 REST 接口,但是接收主机正在使用 self-signed 证书(这不会改变)所以我需要忽略明显的证书验证我收到的错误。
我的初始脚本如下所示:
from urllib.request import Request, urlopen
from urllib.parse import urlencode
post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}
omi_post = Request(url=post_url, data=post_payload, headers=post_headers)
urlopen(omi_post)
如前所述,这会生成以下堆栈跟踪:
Traceback (most recent call last): File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding')) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1239, in request
self._send_request(method, url, body, headers, encode_chunked) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1026, in _send_output
self.send(msg) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 964, in send
self.connect() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1400, in connect
server_hostname=server_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py",
line 407, in wrap_socket
_context=self, _session=session) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py",
line 814, in init
self.do_handshake() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py",
line 1068, in do_handshake
self._sslobj.do_handshake() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py",
line 689, in do_handshake
self._sslobj.do_handshake() ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "send_data.py", line 16, in
urlopen(post_it_already) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 223, in urlopen
return opener.open(url, data, timeout) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 526, in open
response = self._open(req, data) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 544, in _open
'_open', req) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 504, in _call_chain
result = func(*args) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 1361, in https_open
context=self._context, check_hostname=self._check_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 1320, in do_open
raise URLError(err) urllib.error.URLError:
所以我找到了另一个 post 讨论了如何添加 SSL 上下文,我是这样做的:
from urllib.request import Request, urlopen
from urllib.parse import urlencode
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}
post_it_already = Request(url=post_url, data=post_payload, headers=post_headers)
urlopen(post_it_already, context=ctx)
但是这会生成以下堆栈跟踪(无论我如何挥舞拳头):
Traceback (most recent call last): File "send_data.py", line 15, in
urlopen(post_it_already, context=ctx) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 223, in urlopen
return opener.open(url, data, timeout) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 526, in open
response = self._open(req, data) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 544, in _open
'_open', req) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 504, in _call_chain
result = func(*args) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 1361, in https_open
context=self._context, check_hostname=self._check_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py",
line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding')) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1239, in request
self._send_request(method, url, body, headers, encode_chunked) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked) File
"C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py",
line 1064, in _send_output
+ b'\r\n' TypeError: can't concat str to bytes
我不知道为什么它会抱怨将字符串与字节 object 连接起来。我假设它不喜欢我的字符串类型 URL 和我的数据类型负载和 headers?但是我不确定下一步该怎么做。
或者这是一个经典案例,有人使用 2 个单独的示例代码并期望它们一起工作,而实际上它们就像花生和泡泡糖一样?
您的 post_payload
应该是 'bytes' 类型而不是 'str'。
来自Python docs:
class urllib.request.Request ...
...
For an HTTP POST request method, data should be a buffer in the standard application/x-www-form-urlencoded format. The urllib.parse.urlencode() function takes a mapping or sequence of 2-tuples and returns an ASCII string in this format. It should be encoded to bytes before being used as the data parameter.
...
您可以使用 .encode()
方法将 post_payload
转换为字节,详见 this Python urllib howto。
这与 SSL 验证问题是分开的,但可能是因为它试图 POST 数据,所以成功建立了 HTTPS 连接。
您可以使用带有请求模块的@contextlib.contextmanager装饰器。这是一种更简单的方法。
下面的代码工作得很好
@contextlib.contextmanager
def no_ssl_verification():
old_request = requests.Session.request
requests.Session.request = partialmethod(old_request,verify=False)
warnings.filterwarnings('ignore', 'Unverified HTTPS request')
yield
warnings.resetwarnings()
requests.Session.request = old_request
上面的代码所做的是,它为 requests.Session.request 生成了一个带有“verify=False
”的部分方法,并过滤掉任何显示“Unverified Https request
”的警告。
with no_ssl_verification:
request = requests.post(
url,
json={
'name' : some_name
},auth(username,password)
)
希望对您有所帮助,如果您找到更好的解决方案,请告诉我。
我需要 post 数据到 REST 接口,但是接收主机正在使用 self-signed 证书(这不会改变)所以我需要忽略明显的证书验证我收到的错误。
我的初始脚本如下所示:
from urllib.request import Request, urlopen
from urllib.parse import urlencode
post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}
omi_post = Request(url=post_url, data=post_payload, headers=post_headers)
urlopen(omi_post)
如前所述,这会生成以下堆栈跟踪:
Traceback (most recent call last): File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 1318, in do_open encode_chunked=req.has_header('Transfer-encoding')) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1239, in request self._send_request(method, url, body, headers, encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1285, in _send_request self.endheaders(body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1234, in endheaders self._send_output(message_body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1026, in _send_output self.send(msg) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 964, in send self.connect() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1400, in connect server_hostname=server_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 407, in wrap_socket _context=self, _session=session) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 814, in init self.do_handshake() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 1068, in do_handshake self._sslobj.do_handshake() File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\ssl.py", line 689, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "send_data.py", line 16, in urlopen(post_it_already) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 223, in urlopen return opener.open(url, data, timeout) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 526, in open response = self._open(req, data) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 544, in _open '_open', req) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 504, in _call_chain result = func(*args) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 1361, in https_open context=self._context, check_hostname=self._check_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 1320, in do_open raise URLError(err) urllib.error.URLError:
所以我找到了另一个 post 讨论了如何添加 SSL 上下文,我是这样做的:
from urllib.request import Request, urlopen
from urllib.parse import urlencode
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
post_url = "https://myserver.mydomain.com:30005/myapipath"
post_payload = { "event": { "Title": "Something, sometime, something, Python"} }
post_headers = {'Content-Type': 'application/xml'}
post_it_already = Request(url=post_url, data=post_payload, headers=post_headers)
urlopen(post_it_already, context=ctx)
但是这会生成以下堆栈跟踪(无论我如何挥舞拳头):
Traceback (most recent call last): File "send_data.py", line 15, in urlopen(post_it_already, context=ctx) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 223, in urlopen return opener.open(url, data, timeout) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 526, in open response = self._open(req, data) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 544, in _open '_open', req) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 504, in _call_chain result = func(*args) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 1361, in https_open context=self._context, check_hostname=self._check_hostname) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\urllib\request.py", line 1318, in do_open encode_chunked=req.has_header('Transfer-encoding')) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1239, in request self._send_request(method, url, body, headers, encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1285, in _send_request self.endheaders(body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1234, in endheaders self._send_output(message_body, encode_chunked=encode_chunked) File "C:\Users\myusername\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1064, in _send_output + b'\r\n' TypeError: can't concat str to bytes
我不知道为什么它会抱怨将字符串与字节 object 连接起来。我假设它不喜欢我的字符串类型 URL 和我的数据类型负载和 headers?但是我不确定下一步该怎么做。
或者这是一个经典案例,有人使用 2 个单独的示例代码并期望它们一起工作,而实际上它们就像花生和泡泡糖一样?
您的 post_payload
应该是 'bytes' 类型而不是 'str'。
来自Python docs:
class urllib.request.Request ...
...
For an HTTP POST request method, data should be a buffer in the standard application/x-www-form-urlencoded format. The urllib.parse.urlencode() function takes a mapping or sequence of 2-tuples and returns an ASCII string in this format. It should be encoded to bytes before being used as the data parameter.
...
您可以使用 .encode()
方法将 post_payload
转换为字节,详见 this Python urllib howto。
这与 SSL 验证问题是分开的,但可能是因为它试图 POST 数据,所以成功建立了 HTTPS 连接。
您可以使用带有请求模块的@contextlib.contextmanager装饰器。这是一种更简单的方法。
下面的代码工作得很好
@contextlib.contextmanager
def no_ssl_verification():
old_request = requests.Session.request
requests.Session.request = partialmethod(old_request,verify=False)
warnings.filterwarnings('ignore', 'Unverified HTTPS request')
yield
warnings.resetwarnings()
requests.Session.request = old_request
上面的代码所做的是,它为 requests.Session.request 生成了一个带有“verify=False
”的部分方法,并过滤掉任何显示“Unverified Https request
”的警告。
with no_ssl_verification:
request = requests.post(
url,
json={
'name' : some_name
},auth(username,password)
)
希望对您有所帮助,如果您找到更好的解决方案,请告诉我。