400 Bad Request With urllib2 for POST - python

I am struggling from 2 days with a post request to be made only using urllib & urllib2. I have limitations in using curl or requests library, as the machine I would need to deploy my code doesn't support any of these.
The post call would be accompanied with a Header and json Body. I am able to make any get call, but POST with Data & Header throws 400 bad requests. Tried and applied all the options available in google/stackoverflow, but nothing solved!
Below is the sample code:--
import urllib
import urllib2
url = 'https://1.2.3.4/rest/v1/path'
headers = {'X-Auth-Token': '123456789sksksksk111',
'Content-Type': 'application/json'}
body = {'Action': 'myaction',
'PressType': 'Format1', 'Target': '/abc/def'}
data = urllib.urlencode(body)
request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request, data)
And on setting debug handler, below is the format of the request that can be traced:--
send: 'POST /rest/v1/path HTTP/1.1\r\nAccept-Encoding: identity\r\nContent-Length: 52\r\nHost: 1.2.3.4\r\nUser-Agent: Python-urllib/2.7\r\nConnection: close\r\nX-Auth-Token: 123456789sksksksk111\r\nContent-Type: application/json\r\n\r\nAction=myaction&PressType=Format1&Target=%2Fabc%2Fdef'
reply: 'HTTP/1.1 400 Bad Request\r\n'
Please note, the same post request works perfectly fine with any REST client and with Requests library. In the debug handler output, if we see, the json structure is Content-Type: application/json\r\n\r\nAction=myaction&PressType=Format1&Target=%2Fabc%2Fdef, can that be a problem!

You can dump the json instead of encoding it. I was facing the same and got solved with it!
Remove data = urllib.urlencode(body) and use urllib2.urlopen(req, json.dumps(data))
That should solve.

Related

Python request gives 415 error while post data

I am getting 415 error while posting data to server. This is my code how can i solve this problem. Thanks in advance!
import requests
import json
from requests.auth import HTTPBasicAuth
#headers = {'content-type':'application/javascript'}
#headers={'content-type':'application/json', 'Accept':'application/json'}
url = 'http://IPadress/kaaAdmin/rest/api/sendNotification'
data = {"name": "Value"}
r = requests.post(url, auth=HTTPBasicAuth('shany.ka', 'shanky1213'),json=data)
print(r.status_code)
According to MDN Web Docs,
The HTTP 415 Unsupported Media Type client error response code
indicates that the server refuses to accept the request because the
payload format is in an unsupported format.
The format problem might be due to the request's indicated
Content-Type or Content-Encoding, or as a result of inspecting the
data directly.
In your case, I think you've missed the headers.
Uncommenting
headers={
'Content-type':'application/json',
'Accept':'application/json'
}
and including headers in your POST request:
r = requests.post(
url,
auth=HTTPBasicAuth('shany.ka', 'shanky1213'),
json=data,
headers=headers
)
should do the trick
import requests
import json
from requests.auth import HTTPBasicAuth
headers = {
'Content-type':'application/json',
'Accept':'application/json'
}
url = 'http://IPadress/kaaAdmin/rest/api/sendNotification'
data = {"name": "Value"}
r = requests.post(
url,
auth=HTTPBasicAuth('shany.ka', 'shanky1213'),
json=data,
headers=headers
)
print(r.status_code)
As a workaround, try hitting your api using Postman. When you can successfully hit the api in postman, generate python code in postman (button is present in the top right corner). You can copy the code in your python project.
Another possible cause is using requests.post when you should be using requests.get or vice versa. I doubt that this is a common problem, but in my case a server that was happy to accept an HTTP GET for a search rejects it with a 415 when HTTP POST is used instead. (Yet another site required that a search be requested using HTTP POST. It was reusing that code that caused my problem.)

python http client module error / inconsistent

I'm getting the following output
301 Moved Permanently --- when using http.client
200 --- when using requests
URL handling "http://i.imgur.com/fyxDric.jpg" passed as arg through command
What I expect is give me 200 status ok response.
This is the body
if scheme == 'http':
print('Ruuning in the http')
conn = http.client.HTTPConnection("www.i.imgur.com")
conn.request("GET", urlparse(url).path)
conn_resp = conn.getresponse()
body = conn_resp.read()
print(conn_resp.status, conn_resp.reason, body)
When using the requests
headers = {'User-Agent': 'Mozilla/5.0 Chrome/54.0.2840.71 Safari/537.36'}
response = requests.get(url, allow_redirects=False)
print(response.status_code)
You are trying to hit imgur over http, but imgur redirects all its request to process over https.
Due to this redirect the issue is occurring.
http module doesnt inherently handle the redirects you need to handle the redirects, where as requests module handles these redirects by itself.
The documentation on the http module includes in its first sentence "It is normally not used directly." Unlike requests it doesn't action the 301 response and follow the redirection in the headers. It instead returns the 301, which you would have to process yourself.

Is this a Post request issue or an SSL verification issue

I'm trying to use a certain company's (not yet public) API. In their documentation they lay out the format of the Token request. Here's a copy of the documentation for a Token request:
POST
https://***.****.com/auth/realms/****/protocol/openid-connec
t/token
Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {base64-encoded-key-and-secret}
Body: grant_type:client_credentials
The authorization key was given to me by them and is of the form 'Basic a3RhdmlfdG...'
I'm trying to write a Post request in python and I'm having issues and I'm not sure if it's my fault or their developers fault. Here's my code:
url = 'https://***.****.com/auth/realms/****/protocol/openid-connect/token'
headers = {'Content-Type':'application/x-www-urlencoded', 'Authorization':'Basic a3RhdmlfdG...'}
body = {'grant_type':'client_credentials'}
response = requests.post(url = url, data = json.dumps(body), headers = headers)
print response
At the line where response = ...I'm getting an SSL: CERTIFICATE_VERIFY_FAILED error. I've also tried changing the values in the headers to random values and I get the same error. I can think of three possibilities, either
I'm making the Post request incorrectly
There is a problem with the API
I'm missing a certificate which I have to send with the Post request
Is it one of these issues or is it something else?
They are probably using a self signed cert. You can bypass the verify check by adding 'verify=False'. I would remove that before going to production. It is important that SSL certs are valid.
response = requests.post(url = url, data = json.dumps(body), headers = headers, veryify=False)

Getting the JSON response from a POST request Python

I'm currently posting to a sever like so:
req = urllib2.Request('http://xxx.xxx.xx.xx/upload/')
req.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(req, json_string)
print(response.getcode())
I get a 200 code back however I want to read the JSON the server is sending back. How do I do this? (tying to avoid using the requests library)
I did not get code, because I did not have a url.
Try:
req = urllib2.Request('http://xxx.xxx.xx.xx/upload/')
req.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(req, json_string)
print(response.read())
To get the actual json object from the response not just the json serialised string you need to parse the response with the json library
import json
req = urllib2.Request('http://xxx.xxx.xx.xx/upload/')
req.add_header('Content-Type', 'application/json')
response = urllib2.urlopen(req, json_string)
json_response = json.loads(response.read().decode('ascii'))
The encoding may also be utf-8 depending on what the server sends back yo you.
Alternatively you could use the requests library which I find much easier to interact with, you'll need to install it separately though with pip install requests
import requests, json
response = requests.post('http://xxx.xxx.xx.xx/upload', data={'data': json_string})
if response.ok:
response_json = response.json()
else:
print('Something went wrong, server sent code {}'.format(response.status_code))
requests library docs

Post request using Python urllib

I'm making a request to an api using python3 urllib. This is my code,
headers = {}
headers['Content-Type']='application/x-www-form-urlencoded; charset=UTF-8'
#headers['X-Csrf-Token']= {'mode: cors'}
req = urllib.request.Request(url=URL, headers=headers, method='POST')
res = urllib.request.urlopen(req)
print(res.read())
I get the following response,
urllib.error.HTTPError: HTTP Error 415: Unsupported Media Type
The API endpoint is working fine and I've tested it with Postman. This is the equivalent javascript code which gets the job done,
return fetch(url, { credentials : 'include', method: 'post'})
So I'm assuming I've to find a way to add credentials to the header. Can I do a credentials include parallel in Python or do I have to fetch the specific cookie and set it in the request. Any help appreciated.
The error 415 indicates an issue with 'Content-type'.
'application/x-www-form-urlencoded' does not have any parameters.
https://www.w3.org/TR/html5/iana.html#application/x-www-form-urlencoded
Regarding fetch()'s "credentials", you would need the ability to maintain a session (sending cookies as required).
It is much easier with the requests library's Session
http://docs.python-requests.org/en/master/user/advanced/#session-objects

Categories