Reputation: 69
I'm trying to pass multiple value into server according to the url value.
As I have results value like below
[ { url: 'account/41',
status: '200',
headers:
[ 'content-type = application/json,',
'content-type = application/text' ],
body: [ '{ name: XYZ }' ] },
{ url: 'account/43',
status: '201',
headers: [ 'content-type = application/xml']
body: [ '{ name : ZYX }' ] } ]
here, I'm trying to create a server request/response for above multiple value. I used forEach loop to iterate over like if url = account/41 then body will return [ '{ name: XYZ }' ] } and if url = account/43 then body will return [ '{ name : ZYX }' ]. but it's only taking first element of the results value and giving me below error:
UnhandledPromiseRejectionWarning: Error: Can't set headers after they are sent.
something I'm missing but not sure what ? How can I pass one by one value with proper output.
const http = require('http')
const parse = require('./Parse.js')
// create a server object:
let server = http.createServer(function(request, response) {
parse.allFiles().then( results => {
results.forEach(element => {
if (element.url.includes(request.url) ) {
let headerSplit = ( element.headers + '' ).split('=')
let headername = headerSplit[0]
let headerVal = headerSplit[1]
response.setHeader( headername, headerVal )
response.write( JSON.stringify( element.body ) )
response.statuscode = parseInt( element.status )
response.end()
} else {
response.writeHead(404, {'Content-Type': 'text/html'})
response.end('No Page Found')
}
})
})
})
const port = process.env.PORT || 8080
server.listen(port, function() {
// eslint-disable-next-line no-console
console.log('Listening on port ' + port)
})
I have multiple file which carries own URL, STATUS, HEADERS and BODY . After parsing those values(used Parse function) in a single array I'm getting into the variable called results.
[{"url":"account/41","status":"200","headers":["content-type = application/json,"],"body":["{ name: xyz}"]},
{"url":"account/43","status":"201","headers":["content-type = application/xml"],"body":["{ name : zyx}"]}]
If you iterate over the result you will get the element like {"url":"account/41","status":"200","headers":["content-type = application/json"],"body":["{ name: xyz}"]} and in response if you pass the url i the server like localhost:8080/account/41 , it will return ["{ name : zyx}"]}] as response body.
Upvotes: 0
Views: 89
Reputation: 707148
You have a response.end()
inside a .forEach()
loop. That means you're calling it multiple times. You can only call it once for each request because when you call it, headers are written, all write buffers are flushed and the request is ended (e.g. socket closed). Thus, you can't "end" the request multiple times. Since your results.forEach()
loop is synchronous, it appears you could perhaps put the response.end()
somewhere after the loop is done so it is only called once when all the response.write()
calls in the loop are done.
You will also have to fix something else in your loop because you appear to be deciding somewhere in the middle of the loop that you're going to return a 404 if one of the items in the loop doesn't work. I don't know what logic you really should have there. Perhaps you should skip any item that does pass your if
test and only send a 404 if none matched?
You're also trying to set the status and a particular header over and over inside the loop. Those can only have one value so it isn't clear why you're setting it over and over inside the loop. Only the last iteration of the loop will stick.
So, your logic about how to process the loop is really just flawed. We'd have to know more about what the data looks like and what you want the response to look like for us to know how to rework your loop to work properly.
List of things to fix:
response.end()
once per request.response.statuscode
can only have one value so it is unclear why you're calling it multiple times in the loop.You still haven't really explained what response you want to construct, but I'll take a guess. If you find element.url.includes(request.url)
, then you want to send that response and stop the loop and be done. If you don't find element.url.includes(request.url)
in any one of the results
, then you want to send a 404. If that's the case, you can do that like this:
const server = http.createServer(function(request, response) {
parse.allFiles().then(results => {
// find first element.url that matches our request.url
const match = results.find(element => element.url.includes(request.url));
if (match) {
let headerSplit = (match.headers + '').split('=');
let headername = headerSplit[0];
let headerVal = headerSplit[1];
response.setHeader(headername, headerVal);
response.write(JSON.stringify(match.body));
response.statuscode = parseInt(match.status);
response.end()
} else {
response.writeHead(404, {
'Content-Type': 'text/plain'
})
response.end('No Page Found')
}
});
});
Upvotes: 3