Flask: CORS requests hanging on Chrome

Created on 4 Feb 2017  路  6Comments  路  Source: pallets/flask

I'm seeing some strange behavior I can't really explain. My CORS requests are hanging for long periods 10, 20, 30 seconds and I'm not sure why. It seems to be specific to both Flask and Chrome.

I'm using python 3.4.3, Flask 0.12, and Flask-Cors 3.0.2.

Consider the following Flask server that returns some basic HTML and some javascript that makes and AJAX request to an API.

from flask import Flask

app = Flask(__name__)

@app.route("/page1")
def page1():
    return '''
    <html>
        <head>
            <script>
                function resHandler () {
                    document.getElementById('status').innerHTML = 'done!';
                }

                function gopherIt() {
                    document.getElementById('status').innerHTML = 'making request...';
                    var oReq = new XMLHttpRequest();
                    oReq.addEventListener("load", resHandler);
                    oReq.open("GET", "http://localhost:3000/hang");
                    oReq.send();
                }
            </script>
        </head>
        <body>
            <div>
                <input type="button" value="Hang In There" onclick="gopherIt()" />
                <span id="status">Click the button</span>
            </div>
            <a href="http://localhost:8080/page2">Go to page 2</a>
        </body>
    </html>
    '''

@app.route("/page2")
def page2():
    return '''
    <html>
        <body>
            page 2
        </body>
    </html>
    '''

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Here is the Flask API with CORS enabled:

from flask import Flask, json
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/hang")
def hang10():
    return json.dumps({'iamkule': True})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=3000)

Which renders a page like this:

image

Steps to reproduce:

  1. Click the Go to page 2 link
  2. Click the back browser's button
  3. Click the Hang In There button

You'll see a message next to the button that says "making request..." that basically just sits there while the API request hangs. Sometimes clicking it multiple times kinds of wakes it up and fixes it but not always. Sometimes it will also happen right after you refresh the page. It isn't as consistent as using the back button though.

If you open the Chrome debugger you can see all the XHR requests just sitting there.

image

Here are some interesting points to consider:

  1. This does not happen when the CORS library is not used. If I open Chrome with the same origin policy checks disabled by running open -a Google\ Chrome --args --disable-web-security --user-data-dir and run the app, it will not hang.

  2. This happens in Chrome on both macOS Sierra and Windows 10.

  3. This does not happen in Firefox on Mac or Windows.

  4. This does not happen in node. I rewrote the exact same static server and API using node and express and everything works fine (which is why I'm posting this here).

So it kind of seems like some combination of Flask and Chrome not getting along. Does anyone have any ideas about what's going on here?

Most helpful comment

Sorry to wake up a dead thread but I wanted to leave a comment for the next person that has this issue. (I did today.)

The issue is the way Chrome opens speculative connections to speed up subsequent requests. If the speculative connection is accepted by the server first it hangs the singly threaded server until it times out. Nothing to do with flask itself.

I wrote up what I found here.

All 6 comments

The Flask dev server is single-threaded. Maybe CORS does not re-use a a keep-alive connection but always creates a new one? Try running the dev server with threads enabled (threads=True in the run() call I think)

Wow, great call, that does appear to have fixed it. The call to run looks like this:

app.run(host='0.0.0.0', threaded=True, port=3000)

I'll have to do some research on the threaded setting but thanks for the pointer!

Sorry to wake up a dead thread but I wanted to leave a comment for the next person that has this issue. (I did today.)

The issue is the way Chrome opens speculative connections to speed up subsequent requests. If the speculative connection is accepted by the server first it hangs the singly threaded server until it times out. Nothing to do with flask itself.

I wrote up what I found here.

I just have to say thank you all! You've made my day.

If for whatever reason you don't or cant set threading to true, you can turn the preconnect feature off in chrome and that will fix the issue.

In chrome go to settings / advanced / privacy and turn off 'Use a prediction service to load pages more quickly'

Was this page helpful?
0 / 5 - 0 ratings

Related issues

runfalk picture runfalk  路  4Comments

westonplatter picture westonplatter  路  3Comments

maangulo12 picture maangulo12  路  4Comments

stillesjo picture stillesjo  路  4Comments

greyli picture greyli  路  3Comments