5

I've written code for money for 20+ years, I have no excuse for this question though.

And oh boy have I googled it. I know that there are many semi-identical questions here, and I think I have read all of the responses, and tried all of the patterns suggested. Many of the questions are not particularly well articulated, and my case seems a little paradoxical (all parts work in isolation). Please bear with me and I will do my best.

Using svelte-kit on the front, and fastapi on the back.

First, below is my "Buttons.svelte" component, copied verbatim in its entirety.

<script lang="javascript">

    async function worksJustFine() {
        fetch("https://jsonplaceholder.typicode.com/todos")
            .then(response => {
                console.log(" response", response)
                console.log(" r.json() >", response.clone().json())
                response.json()
                    .then(json => {
                        console.log("json", json)
                    })
                    .catch(error => console.log(error))
            })
    }


    async function doesNotWork() {
        fetch(`http://localhost:8000/api/test_url?test_param=1`)
            .then(response => {
                console.log(" response", response)
                console.log(" r.json() >", response.clone().json())
                response.json()
                    .then(json => {
                        console.log("json", json)
                    })
                    .catch(error => console.log(error))
            })
    }
</script>

<buttons>
    <button class="btn btn-outline-primary btn-lg" on:click={worksJustFine}>OK</button>
    <button class="btn btn-outline-primary btn-lg" on:click={doesNotWork}>NOT OK</button>
</buttons>

<style lang="scss">
</style>

Second, below is the route/view:

@router.get("/api/test_url")
async def test_url(test_param: str):
    try:
        print(f"test_param: {test_param}")
        return {"success": True, "message": "Message", "hooray": True}
    except Exception as e:
        print(repr(e))
        return {"success": False, "message": repr(e), "": True}

The problem manifests like this:

  • The "NOT OK" button initiates a request which never returns, and the network panel shows only the standard pebkac "(pending)" request, seemingly forever. This is true for Chromium and Chrome, though both GET requests above DO work from Firefox (latest and dev).

  • The fastAPI URL works perfectly from curl, from insomnia, and from a direct request from the browser in a new tab, using chrome-stable, chromium and Firefox.

  • If I use a POST request (which is my goal), then it does not work from any browser, at all, ever. Pending, forever. The POST does however work fine when fired from curl, postman etc.

  • Sometimes I click it and walk away. Rarely, after an unspecified time (half hour, hour?) I return - and find that it DID in fact, work - the request went through, the side effects are obvious. I think this has happened in total, twice over three days of struggle.

  • It isn't CORS. If I disable the code below, it becomes a CORS issue, but with this code it seems clear. Also, as above, it works fine from FF, who presumably respects CORS too.

app = FastAPI()
app.add_middleware(CORSMiddleware,
                   allow_origins=["http://localhost:3000"],
                   allow_credentials=True,
                   allow_methods=["*"],
                   allow_headers=["*"])
app.include_router(router)
  • None of my browsers have any addons or adblockers installed. In my main browser (qtwebengine/qutebrowser) I have a single greasemonkey script to fast-forward youtube ads, and a couple of user-css files.

  • One common thread among the posts and articles I have read, is that the situation can be different depending on whether or not the debug tools panel is open. In my case, this does not make any difference at all to the situation.

  • Everything is running on localhost - there are no VMs, no containers... just me and localhost.

  1. Due to the fact that worksJustFine works just fine, it does not appear to be a svelte/javascript issue.

  2. Due to the fact that test_url works fine (as POST or GET) from every source other than the fetch API, it does not appear to be a fastAPI issue.

What am I missing? What further information can I provide?

chromium request (pending)

insomnia request, fastapi has not been restarted, chromium request is still pending

Phil
  • 157,677
  • 23
  • 242
  • 245
rockfruit
  • 81
  • 4
  • Given the provided information I would make a guess its a CORS issue. My personal first step to debugging would be to ensure proper CORS headers are disabled either through browser plugin or modifying your server. See https://stackoverflow.com/questions/10636611/how-does-access-control-allow-origin-header-work and https://stackoverflow.com/questions/65635346/how-can-i-enable-cors-in-fastapi for fastapi config – ug_ Jun 22 '22 at 21:50
  • 1
    You mentioned that it works fine from curl, did you try to use the curl request that your browser is using? On the network tab you can "Copy > Copy as cURL". Might be worth debugging using that, maybe some fastapi middleware is holding onto the request in specific cases – ug_ Jun 22 '22 at 22:43
  • When testing with curl, try and capture the main differences a browser represents, mainly sending an `Origin` header and since you're using `fetch`, not following redirects... `curl -v -H "Origin: http://localhost:3000" "http://localhost::8000/api/test_url?test_param=1"`. – Phil Jun 23 '22 at 23:39
  • @phil thank you. I tried both copying the CURL from browser and adding the `-H Origin` header, and directly using the simple version above with that header; both of these work flawlessly and quickly against the fastAPI GET endpoint. At the same time, it persists in refusing to accept these requests from Chrome. – rockfruit Jun 24 '22 at 03:27
  • There is no virtualisation, no docker or other containers. Just fastapi and svelte-kit rawdogging it on localhost, along with insomnia and my browsers. – rockfruit Jun 24 '22 at 03:28
  • _"rawdogging it on localhost"_... love it, going to remember that one . Last ditch effort, have you tried turning it off and on again? Cleared caches? Try a different PC? Run everything on different ports? – Phil Jun 24 '22 at 03:51
  • Just out of curiosity, I would try with a different request library (like axios for instance) to try and narrow the issue down. Then you'll know if the problem comes from fetch or something else? – Thomas Hennes Jun 24 '22 at 05:52
  • Caches are cleared, browsers have been purged and re-installed/updated with latest versions or older versions... and there's absolutely nothing else running on these ports, I'd know. I tried axios and the problem persists! This means it's certainly^Wprobably a fastAPI issue. I've got a couple of worker threads running there, and some SSE endpoints. Since the GET/POST work flawlessly from any non-browser context, I had not considered these to be an issue - I will remove them at once and report back – rockfruit Jun 25 '22 at 12:31

1 Answers1

3

Thank you for taking time to read and comment here. I have overcome the issue, although I am not purified of residual confusion.

  • I was unware that there was a limit on SSE connections - this is hard-capped at 6 in Chromium (firefox also claims that this is the case, and both are flagged wontfix).

  • I was using exactly 6 SSE connections for different streaming datapoints.

  • I disabled all SSE endpoints, and GET/POST worked perfectly. I then incrementally re-enabled ALL the SSE endpoints....

  • Now, the system is precisely unchanged from its state when I asked my question above! However, the GET request works from Chrome and Chromium, and the POST request works from all browsers.

I understand the source of the error, and I've earmarked SSE as "crap to be replaced by websockets on sight".

Thanks again for taking time to talk to me.

"I wish I could just hug you all... but I'm not gonna"

rockfruit
  • 81
  • 4
  • Hi there rockfruit, I am a bit of a beginner but I seem to have the exam problem but I do not quite understand what you did in this solution codewise? Did you change or add something in the add.corsmiddleware? – Olli Sep 03 '22 at 12:57
  • 1
    I originally thought that it was because I was using six SSE connections. I commented all of them, and then uncommented them one-by-one, and finally I found myself right back where I was - with all six connections, working fine. In the end I began replacing them with proper websockets, it's just as simple, and far more useful. This app is still running though, with three SSE connections and they work fine. I wish I could help you more... IIRC my solution was not a solution at all - I did the same thing, expecting a different result - and I got one. – rockfruit Sep 04 '22 at 20:54
  • 1
    I tried a bunch of CORS stuff - it made no difference at all. It seems as though CORS is only the problem once - then you fix it - and it's never a problem again. – rockfruit Sep 04 '22 at 20:55
  • Thanks so much. it seems that replacing them with websockets does work. I wish I'd understood why but I take this as a win! Cheers!! – Olli Sep 05 '22 at 10:20