I'm building an api with nodejs to interact with both the client(android) and the admin(web).
When the api is started, it works fine for the admin and the views are rendered properly but when I connect the client to the api, I get an error/warning in server console like:
App at port 4003
db connection opened successfully
Categroies Count: 2
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:494:11)
at ServerResponse.setHeader (_http_outgoing.js:501:3)
at ServerResponse.header
(E:\nodeCMSApp\node_modules\express\lib\response.js:767:10)
at ServerResponse.json
(E:\nodeCMSApp\node_modules\express\lib\response.js:264:10)
at Categories.find.select.exec.then.data
(E:\nodeCMSApp\routes\admin_categories.js:20:22)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
(node:13880) UnhandledPromiseRejectionWarning: Unhandled promise
rejection (rejection id: 1): Error: Can't set headers after they are
sent.
(node:13880) [DEP0018] DeprecationWarning: Unhandled promise rejections
are deprecated. In the future, promise rejections that are not handled
will terminate the Node.js process with
a non-zero exit code.
Here's my api code snippet:
router.get('/', (req, res) => {
Categories.find({})
.select('title slug image _id')
.exec()
.then(data => {
if (data) {
res.status(200)
.json({
success: true,
count: data.length,
categories: data
})
// I understand that the problem lies here
res.render('admin/all_categories', {
categories: data
});
} else {
res.render('all_categories', {
categories: null
});
}
})
.catch(error => {
console.error(error);
res.send('Error 404');
});
});
I understand that it's because I have already rendered a view with the response object and I'm calling it again to return some json for the client.
My question is how do I render the view and return json data for the client concurrently withoutany errors?
Thanks.
In your code, you are sending two responses to user if all goes well:
if (data) {
res.status(200).json({
success: true,
count: data.length,
categories: data
});
// I understand that the problem lies here
res.render('admin/all_categories', {
categories: data
});
}
In the moment you perform some call to res.json, res.send, res.redirect, res.render, etc, you are sending the proper headers to user (browser) so, in your case, after res.status(200).json you are trying to send res.render and is not possible because first res.json started sending the result to the user. I guess you want to render all_categories with "data" so you should render the template in backend (compile) before send it to the user.
Related
I'm using Stripe, and trying to send a test webhook to my URL and database hosted by Firebase. When I "send test webhook," I get the following error message in the Stripe Console:
Test Webhook Error: 405
"append .json to your request URI to use the rest API"
My code is a direct copy of the tutorial: https://github.com/GaryH21/Stripe-Webhooks-Tutorial/blob/master/functions/index.js
Here is the code of my index.js:
const functions = require('firebase-functions');
const stripe = require("stripe")(functions.config().keys.webhooks);
const admin = require('firebase-admin')
admin.initializeApp();
const endpointSecret = functions.config().keys.signing;
exports.events = functions.https.onRequest((request, response) => {
let sig = request.headers["stripe-signature"];
try {
let event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret)
return admin.database().ref('/events').push(event)
.then((snapshot) => {
return response.json({ received: true, ref: snapshot.ref.toString() })
})
.catch((err) => {
console.error(err)
return response.status(500).end() // error saving to database
})
} catch (err) {
return response.status(400).end() // signing signature failed
}
})
exports.exampleDataBaseTrigger = functions.database.ref('/events/{eventId}').onCreate((snapshot, context) => {
return console.log({
eventId: context.params.eventid,
data: snapshot.val()
})
})
The only time in the tutorial and in my code that .json is used is in the line: return response.json({ received: true, ref: snapshot.ref.toString() })
Should I be appending .json onto "request" somewhere, such as in request.RawBody?
It isn't a problem with the signing keys, as that would give the 400 Error message, which I already dealt with and fixed.
I would be happy to share the code of other files in my app, but as far as I can tell none of the rest is relevant to the problem. Thank you very much.
I want to open a url and collect its httpcode and error, but I can't get its httpcode in goto().catch.
let result = {};
page.goto(url)
.then(res => {
result['http-code'] = res.status();
})
.catch(err => {
result['http-code'] = '?'; // TODO: get http-code in goto().catch
result['page-error'] = err + '';
})
.then(() => {
res.json(result);
});
This is impossible.
TL;DR
Because the page.goto method will not throw an error when any valid HTTP status code is returned by the remote server, including 404 "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling response.status();
page.goto will throw an error if:
there's an SSL error (e.g. in case of self-signed certificates).
target URL is invalid.
timeout is exceeded during navigation.
the remote server does not respond or is unreachable.
the main resource failed to load.
NOTE
page.goto either throws an error or returns a main resource response. The only exceptions are navigation to about:blank or navigation to the same URL with a different hash, which would succeed and return null.
My axios promise is returning undefined as the response.
Although I can see in the dev tools there is a successful response and a body.
app.$axios.post('auth/refresh')
.then(({ data: { access_token } }) => {
return Promise.resolve(access_token);
});
This code results in the below error:
How come it is undefined when I have the below response?
As far as I can see the request is fine, headers below too:
I am working on an Express App with MongoDB and trying to utilize FeathersJS for all my services. Here I'm running a test try to get an error message from the server to the client, but I have an issue with the response from the error handler. My req headers have the correct application/json stuff, so I assumed the Error Handler should send valid json back.
I know I'm not using the next callback in my function, but when I try to do that it gives the same error, so I'm thinking it has to do with the Error Handler. Any direction here would be greatly appreciated!
The first error log is on the server, which is correct.
Bucket Services
error >>>>> Bucket validation failed
Possibly Unhandled Rejection: Bucket validation failed, Promise { <rejected> 'Bucket validation failed' }
>>>>>> Error: Unexpected token < in JSON at position 0
at convert (/Users/jaruesink/Documents/Projects/Buckets/node_modules/feathers-rest/node_modules/feathers-errors/lib/index.js:365:79)
at toError (/Users/jaruesink/Documents/Projects/Buckets/node_modules/feathers-rest/lib/client/base.js:24:37)
at process._tickCallback (internal/process/next_tick.js:103:7)
my create function within the BucketService class:
create({
amount,
isFund = false,
name,
type,
userID: owner
}, params, next) {
const new_bucket = new Bucket({ name, amount, type, isFund, owner });
return new_bucket.save((error) => {
console.log('error >>>>>', error.message);
if (error) { return Promise.reject(error.message); }
return Promise.resolve(new_bucket);
});
}
my router file:
const feathers = require('feathers');
const errorHandler = require('feathers-errors/handler');
const rest = require('feathers-rest');
const router = feathers();
const LoginService = require('../services/login_service');
const UserService = require('../services/user_service');
const BucketService = require('../services/bucket_service');
// Enable REST services
router.configure(rest());
router.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
router.use('/login', new LoginService());
router.use('/user', new UserService());
router.use('/bucket', new BucketService());
// Set up error handling
router.use(errorHandler());
module.exports = router;
I figured it out, the key was to correctly pass through a callback (next) function as the third parameter to handle errors. FeathersJS handles the Promise Rejections for you on errors. Then in my test I needed to convert the Feathers-Error to JSON before I could get the message.
I changed my test to:
it('can validate an incorrect bucket', (done) => {
const invalid_bucket = {
name: 'Invalid Bucket',
};
bucket_service.create(invalid_bucket, {}, (error) => {
error = error.toJSON();
assert(error.message.length > 0);
done();
});
});
and my create function to:
create({
amount,
isFund = false,
name,
type,
userID: owner
}, params, next) {
const new_bucket = new Bucket({ name, amount, type, isFund, owner });
return new_bucket.save()
.then(created_bucket => Promise.resolve(created_bucket))
.catch(next);
}
In my React app, I am trying to access the error returned from this bit of server code.
User.findByUsername(req.body.username)
.then((foundUsername) => {
if (foundUsername) {
return res.status(422)
.json({
error: 'This username is not available.'
});
}
Here is the action creator on the client side
export const signupUser = ({ displayName, email, password, username }) => {
return (dispatch) => {
axios.post(`${API_URL}/signup`, { displayName, email, password, username })
.then((res) => {
dispatch({ type: AUTH_USER });
localStorage.setItem('token', res.data.token);
browserHistory.push('/');
})
.catch((res) => {
console.log(res.data.error);
});
};
};
What I can't seem to figure out is that I can access res.data.token in my then case but can not get hold of res.data.error in my catch case even though I can see the response come through in the network tab on chrome.
This is what I get if I log res to the console in the catch case
Error: Request failed with status code 422
at createError (eval at 150 (bundle.e3597bf….js:39), :15:15)
at settle (eval at 258 (bundle.e3597bf….js:125), :18:12)
at XMLHttpRequest.handleLoad (eval at 147 (bundle.e3597bf….js:7), :77:7)
logging res in then gives me my desired object. Any help would be appreciated.
There are two keys in the res object.
config and response
And the error message you are looking for is in res.response.data.error