Getting CORS error instead of Error 500 (No 'Access-Control-Allow-Origin' header is present)

Viewed 2498

Yesterday I asked a question about CORS error that I was getting when trying to do a POST request to FastApi backend from Angular app. After a few comments I decided to delete the question to re-check everything better.

So things are a bit weird. In my FastApi backend I have the following functions:

@app.post("/hello")
def read_root(request: Request):
    print(request)
    client_host = request.client.host
    return {"client_host": client_host}

@app.post("/pattern-data")
def pattern_input(payload: PatternReconData) -> Dict:
    # Does stuff and falls over tragically
    return result   # this doesn't happen of course

and in my front-end I'm trying both of these:

    this.apiService.sendRequest('hello', 'howdy').subscribe(
      (response) => {
        console.log(response);
      },
      (error: any) => {
        console.log(error);
      },
      () => {
        console.log('done');
      }
    );
    this.apiService.sendRequest('pattern-data', payload).subscribe(
      (response: SuccessResponse) => {
        console.log(response);
        /* do stuff */
      },
      (error: any) => {
        console.log(error);
      },
      () => {
        console.log('done');
      },
    );

What's strange is that if I test sending some values to 'pattern-data' in Swagger UI it comes back with Error 500 since the script falls over. The 'hello' works just fine.

Swagger UI response

Similarly, going from the front-end app if I poke the .../hello I get the expected response:

{client_host: '<some valid ip>'}

but when trying to send values to .../pattern-data results in CORS error:

Access to XMLHttpRequest at 'http://<my-backend-server>/pattern-data' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Yet I know that the backend had successfully received the payload because if I look at backend logs I see this.:

2021-09-16 02:42:38.0130,main,DEBUG,Pattern name received from front-end {data}

So this suggests that the pre-flight check was successful and web app was allowed to communicate with the backend so it all has nothing to do with CORS.

This is a bit confusing and caused me quite a lot of grief having spent time researching CORS and how to deal with CORS errors, while in reality my issue has nothing to do with it.

I don't understand why I'm not getting an Error 500 but a CORS error instead. Is this because the back-end simply fails to send a response and browser (Chrome) interprets no response as not having necessary headers and shows CORS error?

This is from Chrome dev tools Headers section. Poking /hello:

Request URL: http://<my-backend-server>/hello
Request Method: POST
Status Code: 200 OK
Remote Address: <some valid ip>
Referrer Policy: strict-origin-when-cross-origin
access-control-allow-credentials: true
access-control-allow-origin: http://localhost:4200
content-length: 31
content-type: application/json
date: Thu, 16 Sep 2021 02:43:09 GMT
server: uvicorn
vary: Origin

sending data to /pattern-data:

Request URL: http://<my-backend-server>/pattern-data
Referrer Policy: strict-origin-when-cross-origin
content-length: 21
content-type: text/plain; charset=utf-8
date: Thu, 16 Sep 2021 02:43:09 GMT
server: uvicorn
1 Answers

When the error happens, the expected CORS headers on the response are not present (since an exception happened, the middleware does not run).

As the expected CORS headers are missing, the browser doesn't have any other option than returning a CORS error, even if the underlying error is a 500 error. If it did return more information, then the browser would leak information that it wasn't allowed to read (since there is no CORS header present).

CORS only protect you against compliant clients (i.e. proper browsers) not letting third party sites make requests on behalf of the browser's user; it does not stop any other person from making a random request against your service with curl or something similar (but they wouldn't have access to the information that would make it possible to make the request in the context of the browser's user).

Related