I'm working on my python project and I migrated from python2.6 to python 3.6. So I had to replace urllib2 with urllib.request ( and .error and .parse ).
But I'm facing an issue I can't solve, here it is...
I want to send a request written in JSON like below :
import json
import urllib2
data= json.dumps({
"jsonrpc":"2.0",
"method":"user.login",
"params":{
"user":"guest",
"password":"password"
}
"id":1,
"auth":None
})
with urllib2 I faced no issue, I just had to create the request with :
req=urllib2.Request("http://myurl/zabbix/api_jsonrpc.php",data,{'Content-type':'application/json})
send it with:
response=urllib2.urlopen(req)
and it was good but now with urllib.request, I have met many error raised by the library. check what I did ( the request is the same within 'data') :
import json
import urllib.request
data= json.dumps({
"jsonrpc":"2.0",
"method":"user.login",
"params":{
"user":"guest",
"password":"password"
}
"id":1,
"auth":None
})
req = urllib.request.Request("http://myurl/zabbix/api_jsonrpc.php",data,{'Content-type':'application/json})
response = urllib.request.urlopen(req)
and I get this error :
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/tmp/Python-3.6.1/Lib/urllib/request.py", line 223, in urlopen
return opener.open(url, data, timeout)
File "/tmp/Python-3.6.1/Lib/urllib/request.py", line 524, in open
req = meth(req)
File "/tmp/Python-3.6.1/Lib/urllib/request.py", line 1248, in do_request_
raise TypeError(msg)
TypeError: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.
So I inquired about this and learned that I must use the function urllib.parse.urlencode() to convert my request into bytes, so I tried to use it on my request :
import urllib.parse
dataEnc=urllib.parse.urlencode(data)
another error occured :
Traceback (most recent call last):
File "/tmp/Python-3.6.1/Lib/urllib/parse.py", line 842, in urlencode
raise TypeError
TypeError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/tmp/Python-3.6.1/Lib/urllib/parse.py", line 850, in urlencode
"or mapping object").with_traceback(tb)
File "/tmp/Python-3.6.1/Lib/urllib/parse.py", line 842, in urlencode
raise TypeError
TypeError: not a valid non-string sequence or mapping object
and I realized that json.dumps(data) just convert my array/dictionnary into a string, which is not valid for the urllib.parse.urlencode function, soooooo I retired the json.dumps from data and did this :
import json
import urllib.request
import urllib.parse
data= {
"jsonrpc":"2.0",
"method":"user.login",
"params":{
"user":"guest",
"password":"password"
}
"id":1,
"auth":None
}
dataEnc=urllib.parse.urlencode(data) #this one worked then
req=urllib.request.Request("http://myurl/zabbix/api_jsonrpc.php",data,{'Content-type':'application/json})
response = urllib.request.urlopen(req) #and this one too, but it was too beautiful
then I took a look in the response and got this :
b'{"jsonrpc":"2.0",
"error":{
"code":-32700,
"message":"Parse error",
"data":"Invalid JSON. An error occurred on the server while parsing the JSON text."}
,"id":1}
And I guess it's because the JSON message is not json.dumped !
There is always one element blocking me from doing the request correctly,
so I'm totally stuck with it, if any of you guys have an idea or an alternative I would be so happy.
best Regards
Gozu09
In fact you just need to pass your json data as a byte sequence like this:
data= {
"jsonrpc":"2.0",
"method":"user.login",
"params":{
"user":"guest",
"password":"password"
}
"id":1,
"auth":None
}
req = urllib.request.Request(
"http://myurl/zabbix/api_jsonrpc.php",
data=json.dumps(data).encode(), # Encode a string to a bytes sequence
headers={'Content-type':'application/json}
)
POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str
This error means that the data
argument is expected to be an iterables of bytes.
st = "This is a string"
by = b"This is an iterable of bytes"
by2 = st.encode() # Convert my string to a bytes sequence
st2 = by.decode() # Convert my byte sequence into an UTF-8 string
json.dumps()
returns a string, therefore you have to call json.dumps().encode()
to convert it into a byte array.
By the way, urlencode is used when you want to convert a string that will be passed as an url argument (i.e: converting spaces characters to "%20"). The output of this method is a string, not a byte array