2016-07-09 2 views
0

Ich gebe Daten zwischen zwei Express-Middleware als eine meiner Variablen ist in einer Funktion (Middleware 1) gesetzt und muss außerhalb seiner Funktionsumfang zugegriffen werden (in Middleware 2). Wenn ich console.log req.invoice in meiner zweiten Middleware anmelde, loggt es korrekt, so weiß ich, dass ich die Daten zwischen der Middleware korrekt weitergegeben habe, aber beim Versuch, meine Variable zu verwenden, um ein neues Objekt in meiner zweiten Middleware zu erstellen nicht definiert.Übergabe von Daten zwischen Middleware-Logs korrekt, aber Rückgabe undefined innerhalb Objekt

var express = require('express'); 
var app = express(); 
var Invoice = require('../models/Invoice'); 
var router = express.Router(); 
var cookieParser = require('cookie-parser'); 
var bodyParser = require('body-parser'); 
var session = require('express-session'); 
var expressValidator = require('express-validator'); 
var fs = require('fs'); 
//Used to create a pdf invoice 
var PDFDocument = require('pdfkit'); 

//Route 
router.route('/:item') 
    .post(generateInvoice, sendMail, function(req, res){ 

    }); 

//First middleware 

var fileName, dest, invoiceNr; 
function generateInvoice (req, res, next) { 
    //Destination for storing the invoice file 
    dest = __dirname + '/../static/'; 
    //generate invoice nr 
    Invoice.find(function(err, invoices){ 
    if(err) { 
    return res.send(err); 
    } else { 
     invoiceNr = invoices.length + 1; 
     fileName = 'invoice' + invoiceNr + '.pdf'; 
     req.invoicePath = path.resolve(dest + fileName); 
     generate(); 
    } 
    }); 
    //Create the invoice and store in static directory 
    function write() { 
    doc = new PDFDocument(); 
    doc.pipe(fs.createWriteStream(dest + fileName)); 
    doc.text(invoice, 100, 100); 
    console.log('File written > ' + fileName + '\n Destination: ' + dest); 
    doc.end(); 
    } 
    function generate (err){ 
    if (err) 
     throw err; 
    if (invoiceNr !== undefined) { 
     write(); 
    } 
    } 

    next(); 

} 

//Second middleware 
//I'm using mailgun-js to send the invoice via email 
function sendMail(req, res, next){ 
    //Mailgun implementation 
    var api_key = 'MY_KEY'; 
    var domain = 'MY_DOMAIN'; 
    var mailgun = require('mailgun-js')({apiKey: api_key, domain: domain}); 
    var data = { 
    from: 'APP_MAIL', 
    to: '[email protected]', 
    subject: 'Hello', 
    text: 'Should include attachment!', 
    //req.invoicePath is undefined when it should be a filepath 
    attachment: req.invoicePath 
    //when invoicePath was set as a static string, the attachment was included in the email 
    //attachment: '/Users/anton/Desktop/app/src/server/static/invoice27.pdf' 
    }; 

    //again I'm using mailgun-js for sending the emails 
    mailgun.messages().send(data, function (error, body) { 
    console.log('Message body: ' + body); 
    //This works and I get the above: '/Users/anton/Desktop...' in the console 
    console.log('The path to the invoice: ' + req.invoicePath); 
    //Works properly as well 
    console.log('The path is of type: ' + typeof(req.invoicePath)); 
    }); 
    res.end(); 
} 

Ich habe req.invoicePath wie dies ist meine erste Middleware gesetzt.

req.invoicePath = path.resolve(dest + fileName); 

Eine kurze Erklärung, wie E-Mails mit mailgun senden kann auf den mailgun blog here Jede Hilfe bei allen sehr geschätzt, dank bestellt werden!

+0

Wo ist die erste Middleware und die zweite Middleware? Ihre 'sendMail()' Funktion hat keine Ausgabe und ändert nichts, so dass wir unsicher sind, was es tun soll?Bitte zeigen Sie den tatsächlichen Code sowohl für die erste Middleware als auch für die zweite Middleware. – jfriend00

+0

Ok, ich werde sicherstellen, dass meine Frage bearbeitet wird, damit sie einfacher zu befolgen ist. –

Antwort

0

Sie haben asynchrone Timing-Probleme. In Ihrer ersten Middleware rufen Sie next() VOR Ihre Invoice.find()-Funktion ist beendet, so dass die zweite Middleware ausgeführt wird, bevor Sie req.invoicePath setzen.

Um zu beheben, rufen Sie next() nur auf, wenn Sie mit den asynchronen Operationen in der ersten Middleware fertig sind. Sie müssen auch innerhalb von generateInvoice() Ihre Variablen bewegen, so werden sie lokale Variablen geschützt und werden nicht von einer anderen Anforderung vernichtend geschlagen werden, die zur gleichen Zeit im Flug ist:

function generateInvoice (req, res, next) { 
    var fileName, dest, invoiceNr; 
    //Destination for storing the invoice file 
    dest = __dirname + '/../static/'; 
    //generate invoice nr 
    Invoice.find(function(err, invoices){ 
    if(err) { 
    return res.send(err); 
    } else { 
     invoiceNr = invoices.length + 1; 
     fileName = 'invoice' + invoiceNr + '.pdf'; 
     req.invoicePath = path.resolve(dest + fileName); 
     generate(); 
     // move next() here so it is not called until after req.invoicePath is set 
     next(); 
    } 
    }); 
    //Create the invoice and store in static directory 
    function write() { 
    var doc = new PDFDocument(); 
    doc.pipe(fs.createWriteStream(dest + fileName)); 
    doc.text(invoice, 100, 100); 
    console.log('File written > ' + fileName + '\n Destination: ' + dest); 
    doc.end(); 
    } 
    function generate (err){ 
    if (err) 
     throw err; 
    if (invoiceNr !== undefined) { 
     write(); 
    } 
    } 
} 

Es gibt möglicherweise andere asynchrone Probleme auch hier, da ich gehe davon aus, dass write() einige asynchrone Teile haben kann. Und Sie zeigen ein Argument zu generate(), aber Sie übergeben kein Argument. Und wenn generate() die throw err ausgeführt hat, haben Sie keinen Handler, um etwas Intelligentes zu tun.

Änderungen ich gemacht:

  1. Verschoben next() in das Innere des Invoice.find() Rückruf so erst aufgerufen, nachdem req.invoicePath eingestellt ist.
  2. Bewegliche Variablendeklarationen für fileName, dest, invoiceNr innerhalb der generateInvoice()-Funktion, so dass sie für jeden Aufruf der Funktion eindeutig sind und andere Anforderungen im Flug zur gleichen Zeit ihre Werte nicht überschreiten.

Weitere mögliche Probleme:

  1. Sie erklärt generate() einen err Parameter zu akzeptieren, aber Sie sich nicht über eine zu ihm.
  2. Die throw err in generate() würde nicht gefangen werden und nichts nützliches tun, wenn es jemals getroffen wurde.
  3. Sie haben keine Fehlerbehandlung beim Erstellen des PDF-Dokuments.
  4. Wenn die Konstruktion der PDF-Datei asynchron ist, warten Sie nicht darauf, dass sie beendet wird, bevor die nächste Middleware versucht, sie zu verwenden. Es könnte also eine Race-Bedingung geben, in der Sie noch nicht fertig geschrieben sind versuche es zu benutzen.
+0

Vielen Dank für eine gute Erklärung und eine gründliche Antwort! Das hat mein Problem vorerst gelöst. Natürlich muss ich viel lernen, um den Code zuverlässiger zu machen. Ich habe meinen Code ein bisschen mehr aufgeräumt und die generate() Funktion entfernt und jetzt die write() Funktion sofort aufgerufen, was es einfacher macht, auch zu folgen. Meine sendMail() - Funktion wird ausgeführt, aber jetzt wird keine E-Mail gesendet, sondern nur die Protokolle. Natürlich werde ich deine Antwort akzeptieren, da sie mein Problem anspricht, und ich werde das andere sicher herausfinden. Prost! –

Verwandte Themen