3

I have a simple flask server defined like so:

import sys

import flask
from flask import request

app = flask.Flask(__name__)
port = 4057

@app.route('/search', methods=['POST'])
def search():
  request.json['query']
  results = ['fake', 'data']
  return flask.jsonify(results)

if __name__ == '__main__':
 app.config['TEMPLATES_AUTO_RELOAD'] = True
 app.run(host='0.0.0.0', port=port, debug=(port != 80))

I have a simple client defined like this:

import json

import requests

headers = {'content-type': 'application/json'}
resp = requests.post('http://localhost:4057/search', json.dumps({'query': 'foo'}), headers=headers)
print resp.content

The client works, but it takes like 3 seconds to complete the request.

curl completes in like half a second:

curl 'http://localhost:4057/search' -H 'Content-Type: application/json' -d '{"query": "foo"}'

Jesse Aldridge
  • 7,991
  • 9
  • 48
  • 75

3 Answers3

16

Try 127.0.0.1 There maybe some odd name resolution rules fumbling requests.

Ah ok, this is my work machine. I took a look at /etc/hosts and saw ~200 routes defined that I didn't realize were there

As mention in the comments, this does not explain the odd behavior replicated using curl.

salparadise
  • 5,699
  • 1
  • 26
  • 32
  • 1
    Ah ok, this is my work machine. I took a look at `/etc/hosts` and saw ~200 routes defined that I didn't realize were there. – Jesse Aldridge Dec 12 '17 at 06:10
  • 4
    I don't think this answer solve the question essentially. This question is interesting so I have done a wide search. There is a possible reason. As modern OS usually support both ipv6 and ipv4, `localhost` is first resolved to ipv6 address but fail in default timeout window (usually one second), then fallback to ipv4 address. What strange is that curl works well, maybe it perfers ipv4? Or this reason is also not the key point. – Sraw Dec 12 '17 at 06:28
  • @Sraw thanks. I used [this solution](https://superuser.com/a/436944/273248) for configuring IPv4 to take precedence over IPv6 when accessing `localhost`. – yair Dec 29 '19 at 15:39
2

I've recently encountered a similar issue with slow connections from requests to 'localhost', and also found that using '127.0.0.1' was much faster.

After some investigation, I found that in my case, the slow connections on Windows were related to urllib3 (the transport library used by requests) attempting an IPv6 connection first, which is refused since the server is listening on IPv4 only. For Windows only, however, there is an unavoidable 1 sec timeout on socket.connect for refused TCP connections, while the OS 'helpfully' retries the connection up to 3 times. (See: Why do failed attempts of Socket.connect take 1 sec on Windows?).

On Linux, socket.connect fails immediately if the connection is refused, and it can attempt the IPv4 connection without any delay. In addition, some software, like curl, support limiting name resolution to only IPv4 or IPv6. Unfortunately, requests and urllib3 do not support this, and do not seem to plan to support this anytime soon (See: https://github.com/psf/requests/issues/1691)

forcedude0
  • 31
  • 2
0

For those trying to figure this out as no one gave a clear solution here:

I encountered this issue a while ago, and noticed that the Flask test server is not concurrent. The Python Requests takes FOREVER to retrieve the data from your flask app unless you make it concurrent. Enabling "Threaded" in your app.run option will do the trick!

app.run(port=5000, debug=True, threaded=True)
Yongju Lee
  • 241
  • 4
  • 5