Je suis assez nouveau sur Node.js et j'ai quelques problèmes.
J'utilise Node.js 4.10 et Express 2.4.3.
Lorsque j'essaie d'accéder à http://127.0.0.1:8888/auth/facebook , je suis redirigé vers http://127.0.0.1:8888/auth/facebook_callback .
J'ai ensuite reçu l'erreur suivante:
Error: Can't render headers after they are sent to the client.
at ServerResponse.<anonymous> (http.js:573:11)
at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
at ServerResponse.writeHead (http.js:813:20)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Can't set headers after they are sent.
at ServerResponse.<anonymous> (http.js:527:11)
at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
at EventEmitter._tickCallback (node.js:126:26)
Voici mon code:
var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"
var cookieSecret = "node"; // enter a random hash for security
var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({secret: cookieSecret}));
app.use(auth([
auth.Facebook({
appId : fbId,
appSecret: fbSecret,
callback: fbCallbackAddress,
scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
failedUri: '/noauth'
})
]));
app.use(app.router);
});
app.get('/auth/facebook', function(req, res) {
req.authenticate("facebook", function(error, authenticated) {
if (authenticated) {
res.redirect("/great");
console.log("ok cool.");
console.log(res['req']['session']);
}
});
});
app.get('/noauth', function(req, res) {
console.log('Authentication Failed');
res.send('Authentication Failed');
});
app.get('/great', function( req, res) {
res.send('Supercoolstuff');
});
app.listen(8888);
Puis-je savoir ce qui ne va pas avec mon code?
L'objet res
dans Express est une sous-classe de Node.js http.ServerResponse
( lit la source http.js ). Vous êtes autorisé à appeler res.setHeader(name, value)
aussi souvent que vous le souhaitez jusqu'à ce que vous appeliez res.writeHead(statusCode)
. Après writeHead
, les en-têtes sont intégrés et vous ne pouvez appeler que res.write(data)
, et finalement res.end(data)
.
L'erreur "Erreur: impossible de définir les en-têtes après leur envoi". signifie que vous êtes déjà dans l'état Body ou Finished, mais certaines fonctions ont tenté de définir un en-tête ou un statusCode. Lorsque vous voyez cette erreur, essayez de rechercher tout ce qui tente d'envoyer un en-tête après qu'une partie du corps a déjà été écrite. Par exemple, recherchez les rappels appelés accidentellement deux fois ou toute erreur survenant après l'envoi du corps.
Dans votre cas, vous avez appelé res.redirect()
, ce qui a provoqué le passage de la réponse à Terminé. Ensuite, votre code a généré une erreur (res.req
est null
). et puisque l'erreur s'est produite dans votre function(req, res, next)
(pas dans un rappel), Connect a été en mesure de la détecter et a ensuite essayé d'envoyer une page d'erreur 500. Mais comme les en-têtes ont déjà été envoyés, la variable setHeader
de Node.js a lancé l'erreur que vous avez constatée.
La réponse doit être dans Head et reste dans Head:
res.writeContinue()
res.statusCode = 404
res.setHeader(name, value)
res.getHeader(name)
res.removeHeader(name)
res.header(key[, val])
(Express uniquement)res.charset = 'utf-8'
(Express uniquement; affecte uniquement les méthodes spécifiques à Express)res.contentType(type)
(Express uniquement)La réponse doit être dans Head et devient Body:
La réponse peut être soit tête/corps et reste dans corps:
La réponse peut être soit Head/Body et devient Finished:
La réponse peut être soit Head/Body et reste dans son état actuel:
La réponse doit être dans Head et devient Finished:
return next([err])
(Connect/Express uniquement)function(req, res, next)
(Connect/Express uniquement)res.send(body|status[, headers|status[, status]])
(Express uniquement)res.attachment(filename)
(Express uniquement)res.sendfile(path[, options[, callback]])
(Express uniquement)res.json(obj[, headers|status[, status]])
(Express uniquement)res.redirect(url[, status])
(Express uniquement)res.cookie(name, val[, options])
(Express uniquement)res.clearCookie(name[, options])
(Express uniquement)res.render(view[, options[, fn]])
(Express uniquement)res.partial(view[, options])
(Express uniquement)J'ai aussi rencontré cette erreur pendant un moment. Je pense (espère) que je l'ai compris dans ma tête et que je voulais l'écrire ici pour référence.
Lorsque vous ajoutez un middleware à connect ou express (basé sur connect) à l’aide de la méthode app.use
, vous ajoutez des éléments à Server.prototype.stack
dans connect (Au moins avec le npm install connect
actuel, qui est assez différent de le seul github à partir de ce post). Lorsque le serveur reçoit une demande, il effectue une itération sur la pile en appelant la méthode (request, response, next)
.
Le problème est que si l'un des éléments du middleware écrit dans le corps de la réponse ou dans des en-têtes (il semble que ce soit/ou pour une raison quelconque), mais n'appelle pas response.end()
et vous appelez next()
, puis en tant que Server.prototype.handle
central. méthode terminée, il va remarquer que:
response.headerSent
est vrai.Donc, ça jette une erreur. Mais l’erreur qu’elle génère est juste cette réponse de base (du code source connect http.js
:
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);
Ici, il appelle res.setHeader('Content-Type', 'text/plain');
, que vous avez probablement défini dans votre méthode render
, sans appeler response.end (), quelque chose comme:
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
Voici comment tout doit être structuré:
// middleware that does not modify the response body
var doesNotModifyBody = function(request, response, next) {
request.params = {
a: "b"
};
// calls next because it hasn't modified the header
next();
};
// middleware that modify the response body
var doesModifyBody = function(request, response, next) {
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
response.end();
// doesn't call next()
};
app.use(doesNotModifyBody);
app.use(doesModifyBody);
var problemMiddleware = function(request, response, next) {
response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");
next();
};
Le middleware problématique définit l'en-tête de la réponse sans appeler response.end()
et appelle next()
, ce qui confond le serveur de connect.
J'ai eu le même problème et je me suis rendu compte que c'était parce que j'appelais res.redirect
sans instruction return
. La fonction next
était également appelée immédiatement après:
auth.annonymousOnly = function(req, res, next) {
if (req.user) res.redirect('/');
next();
};
Qui aurait dû être:
auth.annonymousOnly = function(req, res, next) {
if (req.user) return res.redirect('/');
next();
};
Beaucoup de gens ont frappé cette erreur. Cela confond avec le traitement asynchrone. Il est fort probable que certains de votre code définissent des en-têtes lors du premier tick, puis vous exécutez un rappel async dans un tick futur. Entre les deux, l'en-tête de réponse est envoyé, mais d'autres en-têtes (comme une redirection 30X) tentent d'ajouter des en-têtes supplémentaires, mais il est trop tard, l'en-tête de réponse ayant déjà été transmis.
Je ne sais pas exactement ce qui cause votre erreur, mais examinez les rappels en tant que domaines potentiels sur lesquels enquêter.
Un conseil simple pour simplifier votre code. Débarrassez-vous de app.configure()
et appelez simplement app.use
directement dans votre écran de premier niveau.
Voir aussi le module everyauth , qui utilise Facebook et une douzaine d’autres fournisseurs d’authentification tiers.
J'ai fait bouillir la tête à ce sujet et cela est dû à une erreur d'inattention dans la gestion des rappels. Les callbacks non retournés font que la réponse soit définie deux fois.
Mon programme avait un code qui valide la requête et interroge la base de données. après avoir validé s'il y avait une erreur, je rappelais index.js avec les erreurs de validation. Et si la validation réussit, elle continue et frappe la base de données avec succès/échec.
var error = validateRequestDetails("create",queryReq);
if (error)
callback(error, null);
else
some code
callback(null, success);
Ce qui se passait, c'est que: la validation de casse échoue, le rappel est appelé et la réponse est définie. Mais pas retourné. Donc, il continue toujours la méthode va à la base de données et frappe le succès/échec. Il appelle à nouveau le même rappel, ce qui a pour effet de définir deux fois la réponse.
Donc, la solution est simple, vous devez "renvoyer" le rappel pour que la méthode ne continue pas à s'exécuter, une fois que l'erreur s'est produite, et donc définit l'objet de réponse une fois
var error = validateRequestDetails("create",queryReq);
if (error)
callback(error, null);
return;
else
some code
callback(null, success);
Ce type d'erreur que vous obtiendrez lorsque vous passerez des déclarations après avoir envoyé une réponse.
Par exemple:
res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");
L'erreur que vous voyez entraînera, car une fois la réponse envoyée, le res.send
suivant ne sera pas exécuté.
Si vous voulez faire quelque chose, vous devriez le faire avant d'envoyer la réponse.
Parfois, vous pouvez avoir cette erreur lorsque vous essayez d’appeler la fonction next () après res.end ou res.send , essayez de supprimer si vous avez next () après res.send ou res.end in votre fonction . Remarque: ici next () signifie que, après avoir répondu au client avec votre réponse ( c.-à-d. res.send ou res.end ), vous essayez toujours d'exécuter du code pour répondre à nouveau, donc ce n'est pas légal.
Exemple :
router.get('/',function (req,res,next){
res.send("request received");
next(); // this will give you the above exception
});
retirez
next()
de la fonction ci-dessus et cela fonctionnera.
Dans mon cas, c'était une réponse 304 (mise en cache) qui était à l'origine du problème.
La solution la plus simple:
app.disable('etag');
Solution alternative ici si vous voulez plus de contrôle:
Dans mon cas, cela s'est produit avec React et postal.js lorsque je ne me suis pas désabonné d'un canal dans le rappel componentWillUnmount
de mon composant React.
Juste penché ça. Vous pouvez transmettre les réponses via cette fonction:
app.use(function(req,res,next){
var _send = res.send;
var sent = false;
res.send = function(data){
if(sent) return;
_send.bind(res)(data);
sent = true;
};
next();
});
Pour ceux qui s'y intéressent et aucune autre solution ne m'a aidé, dans mon cas, cela s'est manifesté sur un itinéraire qui gère le téléchargement des images mais ne gère pastimeouts, et donc si le téléchargement prend trop de temps et expiré, lorsque le rappel a été déclenché après l'envoi de la réponse de délai d'attente, l'appel de res.send () a provoqué le blocage, car les en-têtes étaient déjà configurés pour prendre en compte le délai d'attente.
Cela a été facilement reproduit en définissant un délai très court et en parcourant la route avec une image de taille décente, le crash a été reproduit à chaque fois.
Ajoutez ce middleware et cela fonctionnera
app.use(function(req,res,next){
var _send = res.send;
var sent = false;
res.send = function(data){
if(sent) return;
_send.bind(res)(data);
sent = true;
};
next();
});
Cela se produit lorsque la réponse a été transmise au client et que vous tentez à nouveau de donner une réponse. Vous devez vérifier dans votre code que vous retournez à nouveau quelque part la réponse au client, ce qui provoque cette erreur. Vérifiez et renvoyez la réponse une fois quand vous voulez revenir.
Venu ici de nuxt , le problème venait de la méthode asyncData
du composant, j'ai oublié de return
promise qui récupérait des données et définissait l'en-tête.
Mon problème avec TypeScript était que je n’avais pas fermé la connexion websocket après avoir reçu un message.
WebSocket.on("message", (data) => {
receivedMessage = true;
doSomething(data);
localSocket.close(); //This close the connection, allowing
});
Si vous utilisez des fonctions de rappel, utilisez return
après le bloc err
. C'est l'un des scénarios dans lesquels cette erreur peut se produire.
userModel.createUser(data, function(err, data) {
if(err) {
res.status = 422
res.json(err)
return // without this return the error can happen.
}
return res.json(data)
})
Testé sur la version de noeud v10.16.0
et express 4.16.4
En cas d'erreur, tout ce que j'avais à faire était res.end ().
auth.annonymousOnly = function(req, res, next) {
// add other task here
res.end();
};
L'autre problème auquel vous pourriez être confronté est qu'il existe un code après res.json et res. écrire. Dans ce cas, vous devez utiliser return pour arrêter l'exécution après cela.
auth.annonymousOnly = function(req, res, next) {
if(!req.body.name)
{
res.json({error:"some error"});
return;
}
let comp = "value"; // this is the code after res.json which may cause some problems so you have to use return
};
J'ai eu ce problème quand je faisais nid de promesses. Une promesse à l'intérieur d'une promesse renverrait 200 sur le serveur, mais l'instruction de capture de la promesse extérieure renverrait un 500. Une fois que j'ai résolu ce problème, le problème a disparu.
Dans mon cas, cela se produit en raison de plusieurs rappels. J'ai appelé la méthode next()
plusieurs fois au cours du code
Vérifiez si votre code renvoie plusieurs instructions res.send () pour une seule demande. Comme quand j'avais ce problème ...
J'étais ce problème dans mon application de noeud Restify. L'erreur était que
switch (status) {
case -1:
res.send(400);
case 0:
res.send(200);
default:
res.send(500);
}
Je m'occupais de divers cas en utilisant switch sans écriture. Pour ceux qui connaissent peu le boîtier de commutation, sachez que, sans pause, renvoyez les mots-clés. Le code sous la casse et les lignes suivantes seront exécutés quoi qu'il arrive. Donc, même si je veux envoyer res.send unique, à cause de cette erreur, il retournait plusieurs instructions res.send, ce qui invitait
error cant définit les en-têtes après leur envoi au client. Ce qui a été résolu en ajoutant ceci ou en utilisant return avant chaque méthode res.send () comme return res.send (200)
switch (status) {
case -1:
res.send(400);
break;
case 0:
res.send(200);
break;
default:
res.send(500);
break;
}
Il est très probable qu'il s'agisse davantage d'un nœud. Dans 99% des cas, il s'agit d'un double rappel qui vous oblige à répondre deux fois, ou à deux reprises, etc. Il a résolu mon problème en utilisant next () dans une boucle. Supprimez next () de la boucle ou arrêtez de l'appeler plus d'une fois.
Si vous ne recevez pas d’aide d’en haut: pour les noobs La raison de cette erreur est l’envoi de demandes à plusieurs reprises, laissez-nous comprendre certains cas: - 1. `
module.exports = (req,res,next)=>{
try{
const decoded = jwt.verify(req.body.token,"secret");
req.userData = decoded;
next();
}catch(error){
return res.status(401).json({message:'Auth failed'});
}
next();
}
` dans l'appel ci-dessus next () à deux reprises va générer une erreur
router.delete('/:orderId', (req, res, next) => {
Order.remove({_id:req.params.orderId},(err,data)=>{
if(err){
**res.status(500).json(err);**
}else{
res.status(200).json(data);
}
*res.status(200).json(data);*
})
})
répondre ici est envoyer deux fois vérifier si vous avez déjà envoyé une réponse