0

I've been following this vuejs guide and this flask guide to host my frontend and backend on a raspberry pi.

On my frontend I have this method, which sends an axios POST to the backend.

// path = http://127.0.0.1:5000/shift
// pin, port = 1-8 / SER1

sendByte(pin, port) {
  console.debug(`Setting ${pin} on ${port}`);
  // I'm adding the header to the payload directly
  const payload = {
    data: {
      pin,
      port
    },
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Content-Type": "application/json"
    }
  };
  console.debug(payload);
  axios.post(this.paths.shift, payload);
}

But the payload is not received on my backend (as in there isn't any payload in the uwsgi.log) and instead I get this error in console:

11:53:38.551 new-submission event fired Setup.vue:52
11:53:38.578 Watch-Handler for submissions fired (localStorage updated) Setup.vue:33
11:53:42.312 Setting 1 on SER1 Visualization.vue:83
11:53:42.313
Object { pin: 1, port: "SER1" }
Visualization.vue:85
11:53:45.151 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/shift. (Reason: CORS request did not succeed). 2
11:53:45.154 Error: Network Error createError.js:16
11:53:46.351 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/togglePort. (Reason: CORS request did not succeed). 2
11:53:46.353 Error: Network Error createError.js:16

As it is the most relevant in this error, here's my nginx.conf:

server {
    listen      80;
    server_name fire.com;
    charset utf-8;
    root    /var/www/fire-extinguish-visualizer/dist;
    index   index.html index.htm;    # Always serve index.html for any request
    location / {
        try_files $uri /index.html @fireFlask;
    }
    location /static {
        root /var/www/fire-extinguish-visualizer/dist/;
    }
    location @fireFlask {
        include uwsgi_params;
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' '*';
        # uwsgi_pass unix:/var/www/fire-extinguish-visualizer/server/uwsgi.sock;
        # uwsgi_pass 127.0.0.1:5000;
        uwsgi_pass uwsgi://localhost:5000;
    }
    error_log  /var/log/nginx/vue-app-error.log;
    access_log /var/log/nginx/vue-app-access.log;
}

I've tried numerous configurations and setups and I just can't get this to work.

After all those attempts I don't want to post each nginx.conf or uwsgi.ini I've tried, but for good measure my relevant files are in this gist.

My question is:

How is CORS properly setup on the SENDER and RECEIVER side to avoid this error?

From my understanding it's supposed to work when the following is done:

  • Nginx adds CORS header to POST requests from hosted application
  • uWSGI is configured correctly
  • Flask application has CORS installed and allows cross-origin requests

What else is there? I'm simply puzzled by this cross-origin error by now.

When using http in the uwsgi.conf I can use curl to get the correct response:

pi@firepi:~ $ curl -X POST http://localhost:5000/togglePort -d '{"port":"SER1", "trigger":0}' -H 'Content-Type:
 application/json'
{"status":"success"}
pi@firepi:~ $ curl -X POST http://localhost:5000/shift -d '{"port":"SER1", "pin":1}' -H 'Content-Type: application/json'
{"status":"success"}

Trying a curl with headers and origin gives this:

pi@firepi:~ $ curl --include -X OPTIONS http://localhost:5000/togglePort -d '{"port":"SER1","trigger":0}' --header Access-Control-Request-Method:POST --header Access-Control-Request-Headers:Content-Type --header Origin:http://localhost:80
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Allow: OPTIONS, POST
Access-Control-Allow-Origin: http://localhost:80
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Vary: Origin
Content-Length: 0

I've also stumbled upon uwsgi-tools but don't really know how I can use uwsgi_curl to send specific CORS headers. That would help in troubleshooting this issue though, since I could narrow it down. Any ideas on that?

HackXIt
  • 21
  • 1
  • 8
  • What happens when you go to the Nginx server on port 80 instead of directly to the backend at port 5000? – Slytherin Aug 01 '19 at 14:08
  • Do you mean with the curl? – HackXIt Aug 01 '19 at 14:28
  • `root@firepi:/var/www/fire-extinguish-visualizer/server# curl -X POST http://localhost:80/togglePort -d '{"port":"SER1", "trigger":0}' -H 'Content-Type: application/json'` Response: ` 405 Not Allowed

    405 Not Allowed


    nginx/1.14.2
    `
    – HackXIt Aug 01 '19 at 14:41
  • `root@firepi:/var/www/fire-extinguish-visualizer/server# curl --include -X OPTIONS http://localhost:5000/togglePort \ -d '{"port":"SER1","trigger":0}' \ --header Access-Control-Request-Method:POST \ --header Access-Control-Request-Headers:Content-Type \ --header Origin:http://localhost:80` Response: `curl: (52) Empty reply from server` – HackXIt Aug 01 '19 at 14:46
  • I meant from the Vue app – Slytherin Aug 01 '19 at 14:47
  • `16:56:11.442 Unhandled promise rejection Error: "Network Error" exports createError.js:16 onerror xhr.js:81 es6.promise.js:110 e es6.promise.js:110 exports _perform.js:3 N es6.promise.js:104 exports _invoke.js:5 _task.js:35 b _task.js:21 _ _task.js:25` – HackXIt Aug 01 '19 at 14:56
  • The above is the error I get from the change in the Vue app. – HackXIt Aug 05 '19 at 09:00
  • If you bypass the nginx, you will not have the headers allowing cors, thats why i wanted to see that. Can you please, just for completeness, post headers you recieve when requesting that resource? (for both via nginx and directly to the service). It might help with the problem a little. – Slytherin Aug 05 '19 at 09:44
  • Is it a resource request when doing POST? After all, I'm trying to tell the flask service to do something and not requesting to load something.. Possibly I missunderstand how this works in general, but I'll try to see if I can get those messages, I'm currently creating a test environment. – HackXIt Aug 05 '19 at 11:31
  • Yes, even a POST is affected by the CORS policy in your browser. The fact that you add "Access-Control-Allow-Origin" in your REQUEST does nothing. To have a successful CORS request, the server needs to respond with that header to a "preflight request" which is done by OPTIONS method. If this is ok, the browser then sends the request you actually want. Either the server (nginx) or the server-side-application needs to provide these headers to an OPTIONS request. – Slytherin Aug 05 '19 at 14:19
  • Yea, I think I'm getting closer to the problem here.. I added [open-cors-config](https://enable-cors.org/server_nginx.html) to my nginx.conf (location /) and also adjusted my application according to this [question](https://stackoverflow.com/questions/26980713/solve-cross-origin-resource-sharing-with-flask?rq=1) ... Currently I'm getting 404 Network Errors though. – HackXIt Aug 05 '19 at 15:18
  • I'm still getting the same errors though. `17:45:37.295 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1/togglePort. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). 17:45:37.308 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1/togglePort. (Reason: CORS request did not succeed). 17:45:37.309 Error: "Network Error" exports createError.js:16 onerror xhr.js:81 Visualization.vue:58` – HackXIt Aug 05 '19 at 15:45
  • The network error is a 404. If I add the `location /togglePort {...}` to the nginx.conf then I get the 504 error. I'm never really receiving anything on the Flask-Server, according to the uwsgi.log. So that might be a problem to fix? – HackXIt Aug 05 '19 at 15:51
  • I think I finally fixed it. I deleted all the fuzz in the app.py and just used the plain CORS(app), which is the default and allows all origins. And nginx adds the appropriate headers too.. – HackXIt Aug 05 '19 at 16:11
  • Great, glad you fixed it. Please post an answer so others can see what you did to resolve the issue. – Slytherin Aug 05 '19 at 20:32

1 Answers1

0

This problem occurred due to 3 false configurations in my code/configs.

Correction #1

As @Slytherin suggested in the comments, to make Nginx work properly I need to send the POST to the right port. In my Vue-App I had programmed to send the POST directly to the Flask-App, which results in an CORS Error because no appropriate Headers could be added by Nginx. I fixed it, by fixing the paths:

...
paths: {
        // This is a static Address. I later changed it to a hostname: firepi:80
        togglePort: "http://192.168.137.139:80/togglePort",
        shift: "http://192.168.137.139:80/shift"
      }
...

It should be noted that when using localhost as address that the Browser will actually point to itself. So if you're running your App on Server X and access it from PC A, the path of localhost will actually resolve in PC A and not in Server X. Because of that, a properly setup hostname is recommended.

Correction #2

Because my main error was happening in Problem 1 (Nginx Port), it was quite faulty to steadily look into Problem 2. (CORS-Configuration) To enable CORS, I needed to add the proper headers in the Nginx configuration and also needed to configure CORS in my Flask-App. For Flask I used the default by just using CORS(app).

In my special case I'm allowing all origins because this app is inside a local network, but you should definitly restrict such access when connecting your app to the internet.

Correction #3

Since I'm directing the app to an Address on Port 80, I needed to configure that link inside Nginx:

location /togglePort {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/fire-extinguish-visualizer/server/app_uwsgi.sock;
}
location /shift {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/fire-extinguish-visualizer/server/app_uwsgi.sock;
}
HackXIt
  • 21
  • 1
  • 8