Python requests.post fails in 421 - python

I have the following code in the implementation (uses requests lib):
def call_service(product_ids: Set[str])
response = requests.post(
json={"product_ids": product_ids},
url="http://whatever.com",
)
if response.status_code == 421:
raise MisRedirectedRequest()
I'm using HTTPretty's to simulate this in a test:
#httpretty.activate
def test_http_status_code_421():
httpretty.register_uri(
method=httpretty.POST,
uri="http://whatever.com",
body="{}",
status=421,
)
with pytest.raises(MisRedirectedRequest):
call_service({"123", "543"})
However, MisRedirectedRequest is never raised. The test doesn't pass.
By debugging, I get this in the implementation:
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
The weird thing is that I tried with other HTTP error codes and it works fine (e.g. 420, 500).

After hours of debugging, I discovered that HTTPretty did not support 421.
I created a PR but meanwhile, this is the workaround:
from httpretty.http import STATUSES
STATUSES[421] = "Misdirected Request"
Update: PR is merged.

Related

unable to output status_code inside flask restapi

I am using python 3.8, Flask 1.1.2
While trying to handle errors can't figure out a way to return status code and break code when error is found.
When everything runs fine, program return statement is as follows
return jsonify({'status':'success', 'prediction':pred}), 200
which allow me to access status_code
response = requests.post(url_path, json=data)
print(response.status_code)
>>> 200
However when error arise before reaching end of code I've tried to handle error like this:
code....
try:
code
except KeyError:
return jsonify({'error_message':'something wrong with input'}), 10
code...
return jsonify({"status":"success!", "best_actions":final_actions}), 200
When except statement is executed it outputs ConnectionError: ('Connection aborted.', BadStatusLine('HTTP/1.0 10 UNKNOWN\r\n')) which seems to happen when python client receives empty response according to Connection aborted.', BadStatusLine("''",) on server?
changing except statement like:
expect KeyError:
return jsonify({'error_message':'something wrong with input'})
allow me to obtain response.json() however cannot get response.status_code.
returning with http status_code works:
expect KeyError:
return jsonify({'error_message':'something wrong with input'}), 1xx
above code works fine however I am trying to create custom status_codes therefore I can add detailed reason and solution in my documentation.
Any help or guide to helpful resource would be greatly appreciated, thanks!

Python requests.get() getting error invalid msg

I am trying to make simple script in Python to request API GET responses from Bitcoin mining machines. I need to request a certain JSON key and value {"command":"summary"}. I will extract data from the JSON payload obtained with this to monitor some machines on Zabbix.
If I send the request with bash like this:
# echo '{"cmd":"summary"}' | timeout 1.5 nc IPADDRESS PORT
I will get the data I need, and I could even process it with bash using tr, sed and jq...
However if I send the request with my Python Script I always get "invalid msg". I would much rather do it with Python because I am learning and I can imagine my error is pretty dumb.
This is the python code.
#!/usr/bin/python3
import sys
import logging
import requests
import json
server = 'http://10.136.132.140:4028'
payload = {
"command":"summary"
}
jsonpayload = json.dumps(payload)
print(payload)
print(jsonpayload)
response = requests.get(server,
jsonpayload
)
print(response.json())
This won't work no matter what I do. I have tried using directly payload as params for requests.get to send the string only. Nothing works. Everytime I get the same invalid msg. I have tried typing response = requests.get('http://IPADDRESS:PORT', '{"command":"summary"}') directly, any combination possible of single quotes or double quotes... Nothing works.
I get three exceptions when I call it. The important tracebacks are the following:
http.client.BadStatusLine: STATUS=E,When=1608811559,Code=14,Msg=invalid cmd,Description=whatsminer v1.1
urllib3.exceptions.ProtocolError: ('Connection aborted.', BadStatusLine('STATUS=E,When=1608811559,Code=14,Msg=invalid cmd,Description=whatsminer v1.1'))
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.',
BadStatusLine('STATUS=E,When=1608811559,Code=14,Msg=invalid
cmd,Description=whatsminer v1.1'))
What am I doing wrong here?
Thanks for your help in advance!
If you want to send a json payload, try this:
server = '' # server url
payload = {
"command":"summary"
}
response = requests.get(server, json=payload)

Retry for 5XX error occurrence on REST Call - POST Method

I am trying to do one REST API call for POST method.
There will be around 500 plus calls to the same endpoint from different hosts.
It is resulting in 503 error, Hence I tried to achieve the retry mechanism using Retry function of requests module.
Even though after implementing the retry function still am getting same error.
Code snippet is as below:
import requests
requests.packages.urllib3.disable_warnings()
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import json
s = requests.Session()
retries = Retry(total=3, backoff_factor=0.3, status_forcelist=[502, 503, 504],
method_whitelist=frozenset(['GET', 'POST']))
s.mount('https//', HTTPAdapter(max_retries=retries))
s.mount('http//', HTTPAdapter(max_retries=retries))
response = s.post(url, json=json_payload, headers=headers)
Still am getting an error with 503.
Already gone through previous answers for same pattern of question, But i don't find more information regarding this.
Note: Here script is executed at same time from 525 hosts so around 500 plus hosts will try to trigger the call to the url(internal url), so here 350 hosts i am getting proper 200 response, other end up in 503 error.
Correct me if I am missing something here, Any help is appreciated.
It was basically typos in code, which were causing retry failure mechanism which were not working well.
s.mount('https://', HTTPAdapter(max_retries=retries))
s.mount('http://', HTTPAdapter(max_retries=retries))
Missed to add ":" in "http"/"https". after adding ":" it worked well

Python Requests post times out despite timeout setting

I am using the Python Requests module (v. 2.19.1) with Python 3.4.3, calling a function on a remote server that generates a .csv file for download. In general, it works perfectly. There is one particular file that takes >6 minutes to complete, and no matter what I set the timeout parameter to, I get an error after exactly 5 minutes trying to generate that file.
import requests
s = requests.Session()
authPayload = {'UserName': 'myloginname','Password': 'password'}
loginURL = 'https://myremoteserver.com/login/authenticate'
login = s.post(loginURL, data=authPayload)
backupURL = 'https://myremoteserver.com/directory/jsp/Backup.jsp'
payload = {'command': fileCommand}
headers = {'Connection': 'keep-alive'}
post = s.post(backupURL, data=payload, headers=headers, timeout=None)
This times out after exactly 5 minutes with the error:
File "/usr/lib/python3/dist-packages/requests/adapters.py", line 330, in send
timeout=timeout
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 612, in urlopen
raise MaxRetryError(self, url, e)
urllib3.exceptions.MaxRetryError: > HTTPSConnectionPool(host='myremoteserver.com', port=443): Max retries exceeded with url: /directory/jsp/Backup.jsp (Caused by < class 'http.client.BadStatusLine'>: '')
If I set timeout to something much smaller, say, 5 seconds, I get a error that makes perfect sense:
urllib3.exceptions.ReadTimeoutError:
HTTPSConnectionPool(host='myremoteserver.com', port=443): Read
timed out. (read timeout=5)
If I run the process from a browser, it works fine, so it doesn't seem like it's the remote server closing the connection, or a firewall or something in-between closing the connection.
Posted at the request of the OP -- my comments on the original question pointed to a related SO problem
The clue to the problem lies in the http.client.BadStatusLine error.
Take a look at the following related SO Q & A that discusses the impact of proxy servers on HTTP requests and responses.

Max retries exceeded with URL in requests

I'm trying to get the content of App Store > Business:
import requests
from lxml import html
page = requests.get("https://itunes.apple.com/in/genre/ios-business/id6000?mt=8")
tree = html.fromstring(page.text)
flist = []
plist = []
for i in range(0, 100):
app = tree.xpath("//div[#class='column first']/ul/li/a/#href")
ap = app[0]
page1 = requests.get(ap)
When I try the range with (0,2) it works, but when I put the range in 100s it shows this error:
Traceback (most recent call last):
File "/home/preetham/Desktop/eg.py", line 17, in <module>
page1 = requests.get(ap)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 55, in get
return request('get', url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 378, in send
raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='itunes.apple.com', port=443): Max retries exceeded with url: /in/app/adobe-reader/id469337564?mt=8 (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)
Just use requests features:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry = Retry(connect=3, backoff_factor=0.5)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
session.get(url)
This will GET the URL and retry 3 times in case of requests.exceptions.ConnectionError. backoff_factor will help to apply delays between attempts to avoid failing again in case of periodic request quota.
Take a look at urllib3.util.retry.Retry, it has many options to simplify retries.
What happened here is that itunes server refuses your connection (you're sending too many requests from same ip address in short period of time)
Max retries exceeded with url: /in/app/adobe-reader/id469337564?mt=8
error trace is misleading it should be something like "No connection could be made because the target machine actively refused it".
There is an issue at about python.requests lib at Github, check it out here
To overcome this issue (not so much an issue as it is misleading debug trace) you should catch connection related exceptions like so:
try:
page1 = requests.get(ap)
except requests.exceptions.ConnectionError:
r.status_code = "Connection refused"
Another way to overcome this problem is if you use enough time gap to send requests to server this can be achieved by sleep(timeinsec) function in python (don't forget to import sleep)
from time import sleep
All in all requests is awesome python lib, hope that solves your problem.
Just do this,
Paste the following code in place of page = requests.get(url):
import time
page = ''
while page == '':
try:
page = requests.get(url)
break
except:
print("Connection refused by the server..")
print("Let me sleep for 5 seconds")
print("ZZzzzz...")
time.sleep(5)
print("Was a nice sleep, now let me continue...")
continue
You're welcome :)
I got similar problem but the following code worked for me.
url = <some REST url>
page = requests.get(url, verify=False)
"verify=False" disables SSL verification. Try and catch can be added as usual.
pip install pyopenssl seemed to solve it for me.
https://github.com/requests/requests/issues/4246
Specifying the proxy in a corporate environment solved it for me.
page = requests.get("http://www.google.com:80", proxies={"http": "http://111.233.225.166:1234"})
The full error is:
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='www.google.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'))
It is always good to implement exception handling. It does not only help to avoid unexpected exit of script but can also help to log errors and info notification. When using Python requests I prefer to catch exceptions like this:
try:
res = requests.get(adress,timeout=30)
except requests.ConnectionError as e:
print("OOPS!! Connection Error. Make sure you are connected to Internet. Technical Details given below.\n")
print(str(e))
renewIPadress()
continue
except requests.Timeout as e:
print("OOPS!! Timeout Error")
print(str(e))
renewIPadress()
continue
except requests.RequestException as e:
print("OOPS!! General Error")
print(str(e))
renewIPadress()
continue
except KeyboardInterrupt:
print("Someone closed the program")
Here renewIPadress() is a user define function which can change the IP address if it get blocked. You can go without this function.
Adding my own experience for those who are experiencing this in the future. My specific error was
Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'
It turns out that this was actually because I had reach the maximum number of open files on my system. It had nothing to do with failed connections, or even a DNS error as indicated.
When I was writing a selenium browser test script, I encountered this error when calling driver.quit() before a usage of a JS api call.Remember that quiting webdriver is last thing to do!
i wasn't able to make it work on windows even after installing pyopenssl and trying various python versions (while it worked fine on mac), so i switched to urllib and it works on python 3.6 (from python .org) and 3.7 (anaconda)
import urllib
from urllib.request import urlopen
html = urlopen("http://pythonscraping.com/pages/page1.html")
contents = html.read()
print(contents)
just import time
and add :
time.sleep(6)
somewhere in the for loop, to avoid sending too many request to the server in a short time.
the number 6 means: 6 seconds.
keep testing numbers starting from 1, until you reach the minimum seconds that will help to avoid the problem.
It could be network config issue also. So, for that u need to re-config ur network confgurations.
for Ubuntu :
sudo vim /etc/network/interfaces
add 8.8.8.8 in dns-nameserver and save it.
reset ur network : /etc/init.d/networking restart
Now try..
Adding my own experience :
r = requests.get(download_url)
when I tried to download a file specified in the url.
The error was
HTTPSConnectionPool(host, port=443): Max retries exceeded with url (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
I corrected it by adding verify = False in the function as follows :
r = requests.get(download_url + filename)
open(filename, 'wb').write(r.content)
Check your network connection. I had this and the VM did not have a proper network connection.
I had the same error when I run the route in the browser, but in postman, it works fine. It issue with mine was that, there was no / after the route before the query string.
127.0.0.1:5000/api/v1/search/?location=Madina raise the error and removing / after the search worked for me.
This happens when you send too many requests to the public IP address of https://itunes.apple.com. It as you can see caused due to some reason which does not allow/block access to the public IP address mapping with https://itunes.apple.com. One better solution is the following python script which calculates the public IP address of any domain and creates that mapping to the /etc/hosts file.
import re
import socket
import subprocess
from typing import Tuple
ENDPOINT = 'https://anydomainname.example.com/'
ENDPOINT = 'https://itunes.apple.com/'
def get_public_ip() -> Tuple[str, str, str]:
"""
Command to get public_ip address of host machine and endpoint domain
Returns
-------
my_public_ip : str
Ip address string of host machine.
end_point_ip_address : str
Ip address of endpoint domain host.
end_point_domain : str
domain name of endpoint.
"""
# bash_command = """host myip.opendns.com resolver1.opendns.com | \
# grep "myip.opendns.com has" | awk '{print $4}'"""
# bash_command = """curl ifconfig.co"""
# bash_command = """curl ifconfig.me"""
bash_command = """ curl icanhazip.com"""
my_public_ip = subprocess.getoutput(bash_command)
my_public_ip = re.compile("[0-9.]{4,}").findall(my_public_ip)[0]
end_point_domain = (
ENDPOINT.replace("https://", "")
.replace("http://", "")
.replace("/", "")
)
end_point_ip_address = socket.gethostbyname(end_point_domain)
return my_public_ip, end_point_ip_address, end_point_domain
def set_etc_host(ip_address: str, domain: str) -> str:
"""
A function to write mapping of ip_address and domain name in /etc/hosts.
Ref: https://stackoverflow.com/questions/38302867/how-to-update-etc-hosts-file-in-docker-image-during-docker-build
Parameters
----------
ip_address : str
IP address of the domain.
domain : str
domain name of endpoint.
Returns
-------
str
Message to identify success or failure of the operation.
"""
bash_command = """echo "{} {}" >> /etc/hosts""".format(ip_address, domain)
output = subprocess.getoutput(bash_command)
return output
if __name__ == "__main__":
my_public_ip, end_point_ip_address, end_point_domain = get_public_ip()
output = set_etc_host(ip_address=end_point_ip_address, domain=end_point_domain)
print("My public IP address:", my_public_ip)
print("ENDPOINT public IP address:", end_point_ip_address)
print("ENDPOINT Domain Name:", end_point_domain )
print("Command output:", output)
You can call the above script before running your desired function :)
My situation is rather special. I tried the answers above, none of them worked. I suddenly thought whether it has something to do with my Internet proxy? You know, I'm in mainland China, and I can't access sites like google without an internet proxy. Then I turned off my Internet proxy and the problem was solved.
In my case, I am deploying some docker containers inside the python script and then calling one of the deployed services. Error is fixed when I add some delay before calling the service. I think it needs time to get ready to accept connections.
from time import sleep
#deploy containers
#get URL of the container
sleep(5)
response = requests.get(url,verify=False)
print(response.json())
First I ran the run.py file and then I ran the unit_test.py file, it works for me
Add headers for this request.
headers={
'Referer': 'https://itunes.apple.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
requests.get(ap, headers=headers)
I am coding a test with Gauge and I encountered this error as well, it was because I was trying to request an internal URL without activating VPN.

Categories