Search code examples
pythonpython-requestsurllib

Replace POST request from Requests to urrlib cause 404 Error


I have a code for opening a door with requests like this

from requests import post as req_post

HEADER = {"Authorization": Bearer 097....} # some private number
ACCESS_LINK= https://api.akerun.com/v5/organizations/.../jobs/unlock # some private link

x = req_post(ACCESS_LINK, headers=HEADER)
print(x.header)

will open the door and reply something like this with some private data

{'Date': 'Tue, 06 Oct 2020 01:14:15 GMT', 'Content-Type': 'application/json', 'Content-Length': '23', 'Connection': 'keep-alive', 'Server': 'nginx', 'Strict-Transport-Security': 'max-age=31536000', 'ETag': ... Cache-Control': 'max-age=0, private, must-revalidate', 'Set-Cookie': ..., 'X-Runtime': '0.185443'}

So when I'm doing the same with urllib like this

a = "https://api.akerun.com/v5/organizations/.../jobs/unlock"
b = {"Authorization": "Bearer 097..."}

from urllib import request, parse

req =  request.Request(a, headers=b) 
resp = request.urlopen(req)

it throws an error

Traceback (most recent call last):
  File "/home/suomi/kaoiro/kaoiro/test.py", line 10, in <module>
    resp = request.urlopen(req)
  File "/usr/lib/python3.8/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python3.8/urllib/request.py", line 531, in open
    response = meth(req, response)
  File "/usr/lib/python3.8/urllib/request.py", line 640, in http_response
    response = self.parent.error(
  File "/usr/lib/python3.8/urllib/request.py", line 569, in error
    return self._call_chain(*args)
  File "/usr/lib/python3.8/urllib/request.py", line 502, in _call_chain
    result = func(*args)
  File "/usr/lib/python3.8/urllib/request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 404: Not Found

Why? Is an requests request different from that one from urllib?


Solution

  • The problem most likely is that urllib is performing a GET instead of a POST request in your case.

    From the docs:

    class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

    ...

    method should be a string that indicates the HTTP request method that will be used (e.g. 'HEAD'). If provided, its value is stored in the method attribute and is used by get_method(). The default is 'GET' if data is None or 'POST' otherwise. Subclasses may indicate a different default method by setting the method attribute in the class itself.

    So using

    req = request.Request(a, headers=b, method='POST') 
    

    should probably work.