-3

I am trying to make a low dependency JavaScript to show temperature of raspberry pi. The server sends a JSON as a response to get request and the Client shows a web page.

The server is working as intended,I have checked in browser and using postman

const { spawn } = require("child_process");
const http = require('http');

http.createServer((req, res) => {
    if (req.url === '/') {
        res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        const temp = spawn('cat', ['/sys/class/thermal/thermal_zone0/temp']);
        temp.stdout.on('data', function (data) {
            data = data / 1000;
            console.log('Temperature: ' + data + '°C');
            res.end(JSON.stringify({"temp":data}));
        });
        temp.stderr.on('data', function (data) {
            res.end(JSON.stringify({"temp":"Unavailable"}));
        });
    }
    else {
        res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });
        res.end(JSON.stringify({"temp":"Unavailable"}));
    }
}).listen((process.argv[2] || 64567), () => {
    console.log('Server listening on http://localhost:' + (process.argv[2] || 64567));
});

This is the client side code

<body>
    <script defer>
        await fetch('http://localhost:64567',{mode: 'no-cors'}).then(res => JSON.parse(res)).then(temp => document.getElementById("value").innerHTML = temp.temp);
        // SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data


        /*
        await fetch('http://localhost:64567',{mode: 'no-cors'}).then(res => res.json()).then(temp => document.getElementById("value").innerHTML = temp.temp)
        // SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data

        await fetch('https://api.npoint.io/d5a7160bab77dd869b82').then(res => res.json()).then(temp => document.getElementById("value").innerHTML = temp.temp)
        // This one works
        */
    </script>
    <h3>Temperature:<span id="value"> </span> °C</h3>
</body>

but when I try to use fetch api in the client side, JSON.parse gives two different types of errors for different approaches, but when I use a publicly hosted JSON bin it works.

Expectation: Fetch JSON being fetched and parsed correctly.

Tried:

  1. Two different approaches to parse JSON
  2. Use a different host for JSON
  • Have you checked the browser "Network" tab to inspect what the server is actually sending? – Pointy Jan 27 '23 at 15:08
  • Also mixing `await` with `.then()` callbacks is not a good habit. – Pointy Jan 27 '23 at 15:09
  • 2
    Why are you using `mode: "no-cors"`? This will make your Response opaque and you'll be unable to read anything from it. If your script is able to reach `localhost` at all, I guess cross-origin isn't that much of an issue, is it? – Kaiido Jan 27 '23 at 15:20
  • @Kaiido it maybe is, when the backend and the frontend are served by different processes (which seems the case if the above is all of the backend's code) – derpirscher Jan 27 '23 at 15:23
  • @Pointy Yes the requests are being received by the back end, I have checked the network tab of browser too. – user9541267 Jan 27 '23 at 15:30
  • @Kaiido The back end is a node server that will be always listening but the front end is just a page being served using `npx serve` – user9541267 Jan 27 '23 at 15:33
  • @derpirscher my point was that if their front-end is able to reach localhost:whateverport they must be running it from localhost:atleastanotherport and thus from the same machine. So I hope they trust enough the scripts running there for the protections offered by the same origin policies to not matter that much. – Kaiido Jan 27 '23 at 15:39
  • @Kaiido Why? I can perfectly well serve my frontend from `https://example.com`, which can be at any webhosting provider and still try to access `http://localhost:12345` A malicous site may even do that on purpose and try to gather information about my system ... Maybe the attack vector for a simple node backend isn't that yielding. But targeting an IIS, how knows ... – derpirscher Jan 27 '23 at 16:44
  • Kaiido is right. If you want your client to be able to read the response, the request should be made in `cors` mode (the default) and the server should be configured for CORS to allow that client. – jub0bs Jan 28 '23 at 07:21

2 Answers2

1

res is a Response, not the text. Use res.json() to parse the body text as JSON.

fetch('http://localhost:64567').then(res => res.json())
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • I have already tired this, this gives me a SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data – user9541267 Jan 27 '23 at 15:17
  • @user9541267 Try checking `res.text()`. What text is being returned by the server? – Unmitigated Jan 27 '23 at 15:18
  • `JSON.parse(res)` is of course a problem and OP must use `res.json()` instead. But the source of the problem is probably like @Kaiido commented above, the `mode: 'no-cors'` which prevents JS to read the response ... – derpirscher Jan 27 '23 at 15:27
  • @user9541267 Why are you using `{mode: 'no-cors'}`? – Unmitigated Jan 27 '23 at 15:28
  • fetch('http://localhost:64567',{mode: 'no-cors'}).then(res => res.text()).then(tex => console.log(tex)) this just prints an empty string – user9541267 Jan 27 '23 at 15:29
  • @user9541267 You should remove `{mode: 'no-cors'}`. If you're fetching data from a different origin, then you need to set up CORS on the server. – Unmitigated Jan 27 '23 at 15:29
  • @Unmitigated I am using `{mode: 'no-cors'}` as without it the requests get blocked despite both the front end and back end being served on localhost. – user9541267 Jan 27 '23 at 15:36
  • @user9541267 You need to configure CORS allowed origins on the server then. – Unmitigated Jan 27 '23 at 15:37
  • @Unmitigated Thanks, I forgot that I can setup the server to ignore CORS, setting that up makes it work first time. Although I don't get why this is happening can you explain a bit? – user9541267 Jan 27 '23 at 15:45
  • @user9541267 Take a look at this: https://stackoverflow.com/questions/43262121/trying-to-use-fetch-and-pass-in-mode-no-cors – Unmitigated Jan 27 '23 at 15:46
-1

So I figured it out, thanks to @Unmitigated , all I needed to do was set the CORS on the server side and remove mode:no-cors in the client side.

Adding headers like these, in the server was the fix.

const headers = {
    'Access-Control-Allow-Origin': '*', /* @dev First, read about security */
    'Access-Control-Allow-Methods': 'OPTIONS, GET',
    'Access-Control-Max-Age': 2592000, // 30 days
    'Content-Type': 'application/json; charset=utf-8'
    /** add other headers as per requirement */
};
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 30 '23 at 12:41