2017-11-10 4 views
0

데이터를 REST 인터페이스에 게시해야하지만 수신 호스트가 자체 서명 된 인증서를 사용하고 있습니다. (변경하지 않으려 고합니다) 따라서 명백한 인증서 유효성 검사를 무시해야합니다. 오류가 발생했습니다.SSL 인증서 확인없이 urllib을 사용하여 데이터 게시하기

내 초기 스크립트는이처럼 보였다 :

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:

그래서 내가 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) 

그러나 이것은 다음 스택 스택을 생성한다. CE (나는 그것을 내 주먹을 흔들 아무리) :

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

나는 그것이 바이트 객체와 문자열을 연결에 대해 불평 이유에 손실에 있어요. 내 문자열 형식 URL 및 내 데이터 형식 페이로드 및 헤더를 좋아하지 않는다고 가정합니까? 그러나 나는 무엇을 다음에해야하는지 확신 할 수 없다.

아니면 2 개의 샘플 코드를 가져 와서 실제로 땅콩과 버블 껌과 같이 작동 할 것으로 예상되는 고전적인 사례입니까?

답변

0

post_payload은 'str'이 아닌 'bytes'유형이어야합니다. 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.

...

당신은 this Python urllib howto에 설명 된대로 .encode() 방법을 사용하여 바이트 post_payload을 변환 할 수 있습니다.

이것은 SSL 검증 문제와 별개이지만 POST 데이터를 시도했기 때문에 HTTPS 연결이 성공적으로 설정되었습니다.

+0

감사합니다. 나는 맹목적으로 다른 코드 스 니펫에서 코드를 빌드하는 일반적인 함정에 빠졌다. 먼저 설명서를 읽었어야합니다. URL 인코딩에 사용한 .parse를 먼저 추가 한 다음 .encode를 사용하여 연결된 문서마다 정확하게 바이트로 변환합니다. – irwazr

0

요청 모듈 대신 @ contextlib.contextmanager 데코레이터를 사용할 수 있습니다. 훨씬 간단한 방법입니다.

아래 코드

는 무엇 위의 코드가하는 일은이 ' verify=False'로 requests.Session.request에 대한 부분 방법을 생성하고 ' Unverified Https request'라고 경고 필터입니다

@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 

잘 작동합니다.

with no_ssl_verification: 
    request = requests.post( 
          url, 
          json={ 
            'name' : some_name 
           },auth(username,password) 
          ) 

더 나은 해결책을 찾으면 도움이되기를 바랍니다.