Currently
I have an express server that I am running locally to manage requests from a react client.
Problem
When my client is idle (I assume after the client PUT server actions previously), after about 3-5mins, error messages appear in the console logs.
Error Message:
This causes the next client PUT to the server to fail i.e. data is not saved.
Request
I don't have much experience with middleware management, so would appreciate some help on how to diagnose what may be causing this error.
Notes that may be helpful:
sometimes when the client makes too many PUTs to the server, the data fails to save, but there is no error message. I am forced to reload the page.
Extract from Client - App.js
saveData = data => {
console.log("Submitting request to save...");
fetch('/api/v1/savedata', {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(console.log("Save complete!"));
};
Extract from Server.js:
// An api endpoint that saves data from the client
app.put('/api/v1/savedata', (req,res) => {
console.log('Server received request to saveData');
let options = {
files: './data/save.json',
changes: req.body
}
updateJsonFile(options);
});
you didn't sent any response in the API, use res.send or res.json like this:
app.put('/api/v1/savedata', (req,res) => {
console.log('Server received request to saveData');
let options = {
files: './data/save.json',
changes: req.body
}
updateJsonFile(options);
res.json({data: data}) // if you want to send json response
// Note: please don't send response object more than once
});
Related
I send post request to my API that contains userName and password in the body. When I do that with Postman I can get a response which has a body contains a token.
But when I send the same request with fetch in fronted I get a responce with an empty body.
My feth is here:
async function login(){
await fetch('/auth/login',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(
{
'userName' : userName,
'password' : password,
}
)
}
).then(
res => {
console.log(res)
localStorage.setItem('Authorization',JSON.stringify(res))
}
).catch(
err => {
console.log("Erorororor: " + JSON.stringify(err))
}
)
}
What is the problem?
I changed my code to
.then(res => return res.text()).then(data => console.log(data)).catch(...)
and now I can get the result which I want.
TLDR Solution
It's caused by some header settings from the server side (For example, setting Access-Control-Allow-Origin: *
twice will likely cause this issue). By tuning the headers you can fix it.
Details
I met the same issue. It's NOT caused by javascript code as the browser itself doesn't get body either, but headers and cookies are got.
By expanding the timing tab you can see a warning showing the request is not finished!
But the postman can get the body:
When
The same code works in the past. It came out recently. I'm not sure what's changed as there are many things changed, for example, the browser version, the nodejs version upgraded, etc.
Fixed
By tunning the headers in the server side fixed the problem.
To summarize, the results of my form are based on a URL that is submitted, and when the form is submitted, I am fetching data from my express backend.
When I search a url, nothing seems to happen in my console. Then, after about 30 seconds I receive the console errors of
GET https://localhost.com/lookup/url net::ERR_CONNECTION_TIMED_OUT
pointing to the lines of const response = await fetch(url, { and getData ('https://localhost.com/lookup/url') and the error of:
Uncaught (in promise) TypeError: Failed to fetch
Promise.then (async)
(anonymous)
pointing to the line of .then(data => {
culminating in fetch failed loading: GET "https://localhost.com/lookup/url"
The full block of code is below:
document.getElementById('search').addEventListener('submit', function(e) { e.preventDefault(); getData(); })
async function getData(url = '', data = {}) {
const response = await fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
});
return response.json();
}
getData ('https://localhost.com/lookup/url')
.then(data => {
console.log(data);
})
Any insight as to what I would be doing wrong and an answer as to how this could be resolved in order to return json from my backend would be appreciated. Still learning, so apologies for all the errors at once.
Re: comment about port #, this is how I have my port setup
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
```
Using the // in the url will comment out the rest
fetch("https://localhost.com/location/url") seems a bit strange for two reasons:
the name of the local machine typically is localhost and not localhost.com and
you probably don't have a certificate for your local testserver, so you can't use a https connection.
And because you have the wrong domain, fetch() cannot establish a connection to https://localhost.com/location/url. So after the default timeout of 30 seconds, it throws an error.
If, by any chance, the domainname localhost.com is correct (maybe it's just a disguise for the real domainname here in the post), you are probably missing the port. Because https://localhost.com will per default try to connect to port 443.
So you probably want just
getData("http://localhost:port/lookup/url")
or if your server hosting both, the your frontend files and the api, you can simply do
getData("/lookup/url")
If I were to serve the localhost root file a HTML file like so:
app.get('/', (req, res) => res.sendfile('index.html'))
Can I add Javascript files to the HTML document that can't be viewed or touched by the browser?
And if so, is it possible that it can also have access to node api's?
Im new to Express so I have no clue how it works.
You can have the server do some work after receiving parameters from the frontend.
The javascript loaded in the DOM will send a request to the server, the server will do some work, unknown to the frontend JS, then return the result.
On Server:
app.post('/path', (req, res) => {
const json = req.body;
//do work
const resp = {some: 'data'};
res.json(resp);
}
On Frontend
fetch('/path', {
method: 'post',
body: JSON.stringify(data),
headers: { 'Content-type': 'application/json' }
})
.then(res => res.json()) // get json data out of response object
.then(json = > {
// do something with response json
}
You'll want to do some reading on Express and body parsing, as well as using parameters in GET requests as opposed to body in POST requests, also other types of requests.
I have the following code that makes a post request to my Nodejs app on the backend:
fetch('http://localhost:3000/ws', {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
}).then(res => {
return res.json();
}).then(data => {
alert(JSON.stringify(data));
});
Everything works fine, it sends the request and gets the response successfully. The problem is that most of the browsers allows the users to debug my code, they can put a breakpoint where the response is being handled and modify its values.
How can I prevent them from doing that?
You can't apply that kind of control to code running on the client. You should always assume it's untrusted code running on the client. If you need controls, you'll have to apply them on the server.
I have two UIs, one for order.html and one for ledger.html running on two different ports 3000 and 8000 on localhost . On the order page, a user can place an order for an item. Once he places the order, the information is sent as a POST request to server on port 8000.
Below is the post request from the order.html page to server with port 8000
$scope.sendPostRequest=function(){
var dataToBeSent = $scope.postData;
$http({
method: 'POST',
url: 'http://127.0.0.1:8000/receiveOrder',
headers: { 'Content-Type': 'text/plain' },
data: 'some random data'
}).then(function successCallback(response) {
//extracts key:value pairs from the json sent back
$scope.postResponse= someResponse
}, function errorCallback(error) {
// some error handler functions here
})
}
Below is the express code at port 8000 to receive the above request.
app.post('/receiveOrder', function(req, res){
console.log('type of request '+Type(req));
//extract the text passed in data section of the post request
//TODO: Use the data received to update the dashboard, ledger.html
//send some response back as confirmation
});
Once the POST request is received and the data sent is parsed using body-parser, I need to update the UI of ledger.html page to show this.
Basically, ledger.html keeps track of the orders placed by users in real time. It is a dashboard in which fresh orders keep getting added as they are placed. I am stuck in achieving the above.
I have experimented with using socket.io by way of using event-emitters but could not go very far. I have a schema setup for the order data in MongoDB as well in case I need it.
May I have some guidance about what I can use to achieve the above.