TypeError: can't concat bytes to str python3
Question:
I’m trying to send HTTP request in python3
using urllib3
.
Here is code snippet
request_body = {'grant_type':'password','username': username,'password': password}
request_headers = {'Content-Type' : 'application/x-www-form-urlencoded','Authorization': "hash string"}
http = urllib3.PoolManager()
response = http.request('POST', 'https://api/url/endpoint', headers=request_headers, body=request_body)
But when I try to execute it, it throws following error.
TypeError: can’t concat bytes to str
Full traceback
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/request.py", line 70, in request
**urlopen_kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/request.py", line 148, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/poolmanager.py", line 321, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/connectionpool.py", line 600, in urlopen
chunked=chunked)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/connectionpool.py", line 356, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1064, in _send_output
+ b'rn'
Can anybody point out what I’m doing wrong?
EDIT
request_body
type check
>>> type(request_body)
<class 'dict'>
>>> type(request_body['username'])
<class 'str'>
>>> type(request_body['password'])
<class 'str'>
>>> type(request_body['grant_type'])
<class 'str'>
Answers:
I think you meant to use fields
parameter instead of body
.
http.request('POST', 'https://api/url/endpoint', headers=request_headers, fields=request_body)
like in this example
I have found a solution of this problem.
I was trying to get a token from keycloak.
Keycloak excepts a:
POST request
Content-Type: application/x-www-form-urlencoded
With credentials in the body
I read that in https://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.request:
request_encode_body(method, url, fields=None, headers=None, encode_multipart=True, multipart_boundary=None, **urlopen_kw)
Make a request using urlopen() with the fields encoded in the body. This is useful for request methods like POST, PUT, PATCH, etc.
When encode_multipart=True (default), then urllib3.filepost.encode_multipart_formdata() is used to encode the payload with the appropriate content type. Otherwise urllib.urlencode() is used with the ‘application/x-www-form-urlencoded’ content type.
So I successfully completed my request like this:
data = {
'client_id': 'front',
'grant_type': 'password',
'username': settings.AUTH_REST_ADMIN_API_USER,
'password': settings.AUTH_REST_ADMIN_API_PASSWORD
}
r = http.request_encode_body(
'POST',
settings.token_endpoint,
encode_multipart=False,
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': settings.AUTH_AUTHORIZATION
},
fields=data
)
The encode_multipart=False
part of the request_encode_body
method, solved my issue.
When I am using commented payload with json.dump its working fine for me. But when passing a payload as dictionary its failing with error "{‘error’: ‘Invalid grant_type’}".
import http.client
import json
conn = http.client.HTTPSConnection("xyz.com")
# payload = "grant_type=password&username=xyz&password=x#y$z&refresh_token="
content = {
'grant_type': "password",
'username': "xyz",
'password': "x#y$z"
}
headers = {
'content-type': "application/x-www-form-urlencoded",
'accept': "*/*"
}
payload = json.dumps(content)
conn.request("POST", "/oauth2/token", payload, headers)
res = conn.getresponse()
data = json.loads(res.read().decode("utf-8"))
print(data)
I’m trying to send HTTP request in python3
using urllib3
.
Here is code snippet
request_body = {'grant_type':'password','username': username,'password': password}
request_headers = {'Content-Type' : 'application/x-www-form-urlencoded','Authorization': "hash string"}
http = urllib3.PoolManager()
response = http.request('POST', 'https://api/url/endpoint', headers=request_headers, body=request_body)
But when I try to execute it, it throws following error.
TypeError: can’t concat bytes to str
Full traceback
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/request.py", line 70, in request
**urlopen_kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/request.py", line 148, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/poolmanager.py", line 321, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/connectionpool.py", line 600, in urlopen
chunked=chunked)
File "/Users/Mubin/anaconda/lib/python3.6/site-
packages/urllib3/connectionpool.py", line 356, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/Users/Mubin/anaconda/lib/python3.6/http/client.py", line 1064, in _send_output
+ b'rn'
Can anybody point out what I’m doing wrong?
EDIT
request_body
type check
>>> type(request_body)
<class 'dict'>
>>> type(request_body['username'])
<class 'str'>
>>> type(request_body['password'])
<class 'str'>
>>> type(request_body['grant_type'])
<class 'str'>
I think you meant to use fields
parameter instead of body
.
http.request('POST', 'https://api/url/endpoint', headers=request_headers, fields=request_body)
like in this example
I have found a solution of this problem.
I was trying to get a token from keycloak.
Keycloak excepts a:
POST request
Content-Type: application/x-www-form-urlencoded
With credentials in the body
I read that in https://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.request:
request_encode_body(method, url, fields=None, headers=None, encode_multipart=True, multipart_boundary=None, **urlopen_kw)
Make a request using urlopen() with the fields encoded in the body. This is useful for request methods like POST, PUT, PATCH, etc.
When encode_multipart=True (default), then urllib3.filepost.encode_multipart_formdata() is used to encode the payload with the appropriate content type. Otherwise urllib.urlencode() is used with the ‘application/x-www-form-urlencoded’ content type.
So I successfully completed my request like this:
data = {
'client_id': 'front',
'grant_type': 'password',
'username': settings.AUTH_REST_ADMIN_API_USER,
'password': settings.AUTH_REST_ADMIN_API_PASSWORD
}
r = http.request_encode_body(
'POST',
settings.token_endpoint,
encode_multipart=False,
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': settings.AUTH_AUTHORIZATION
},
fields=data
)
The encode_multipart=False
part of the request_encode_body
method, solved my issue.
When I am using commented payload with json.dump its working fine for me. But when passing a payload as dictionary its failing with error "{‘error’: ‘Invalid grant_type’}".
import http.client
import json
conn = http.client.HTTPSConnection("xyz.com")
# payload = "grant_type=password&username=xyz&password=x#y$z&refresh_token="
content = {
'grant_type': "password",
'username': "xyz",
'password': "x#y$z"
}
headers = {
'content-type': "application/x-www-form-urlencoded",
'accept': "*/*"
}
payload = json.dumps(content)
conn.request("POST", "/oauth2/token", payload, headers)
res = conn.getresponse()
data = json.loads(res.read().decode("utf-8"))
print(data)