2016-05-29 12 views
3

den folgenden Code Gegeben:Datei herunterladen und Client-Verbindung trennen?

async function (req, res, next) { 
    const fd = await fs.open("myfile.txt") 
    fs.createReadStream(null, { fd, autoClose: false }) 
    .on('error', next) 
    .on('end',() => fs.close(fd)) 
    .pipe(res) 
} 

Was der Kunde trennt passiert, wenn vor dem Herunterladen der gesamten Datei? d. h. wird end immer noch angerufen werden oder ist der Datei-Deskriptor durchgesickert, und wenn ja, wie kann ich es beheben? Wenn `end 'aufgerufen wird, bedeutet das, dass die gesamte Datei gelesen wird, obwohl der Client nicht mehr darauf hört?

Hinweis, ich weiß, ich könnte dies ohne fd tun, aber das ist eine Vereinfachung von komplexeren Code.

Antwort

2

Es sieht so aus, als ob die Datei nicht geschlossen wird oder zumindest Ihr end Event-Handler nicht aufgerufen wird.

Sie können Test dafür schaffen, aber hier ist meins:

const http = require('http'); 
const fs = require('fs'); 

var server = http.createServer(function (req, res) { 
    console.log('server request received'); 
    const fd = fs.openSync('myfile.txt', 'r'); 
    fs.createReadStream(null, { fd, autoClose: false }) 
     .on('error', err => { 
      console.error('file error', err); 
     }) 
     .on('end',() => { 
      console.log('file end'); 
      fs.close(fd); 
     }) 
     .on('close',() => { 
      console.log('file closed'); 
     }) 
     .pipe(res) 
      .on('error', err => console.error('server stream error', err)) 
      .on('end',() => console.log('server stream end')) 
      .on('close',() => console.log('server stream closed')) 
    ; 
}); 

server.listen(0, 'localhost',() => { 
    const address = server.address(); 

    var req = http.request({port: address.port}, function (res) { 
     res.on('data', data => { 
      console.log('response data'); 
      // Comment next line to read whole file. 
      req.abort(); 
     }); 
     res.on('end',() => { 
      console.log('response ended'); 
      setTimeout(() => server.close(), 1000); 
     }); 
     req.once('abort',() => { 
      console.log('request aborted'); 
     }); 
    }); 

    req.end(() => { 
     console.log('request sent'); 
    }); 
}); 

Ich entfernte async/warten zur Vereinfachung der Test läuft.

Wenn req.abort() genannt wird, i folgende Ausgabe:

request sent 
server request received 
response data 
request aborted 
response ended 
server stream closed 

nach dieser Zeile zu kommentieren, und damit Code gesamte Datei zu lesen:

request sent 
server request received 
response data 
response data 
response data 
response data 
response data 
response data 
file end 
response data 
response ended 

erstellen Test myfile.txt i folgender Befehl verwendet:

dd if=/dev/zero of=myfile.txt bs=1k count=200 
+0

Das ist eigentlich nicht überraschend - ein Set 'autoClose: fa lse' explizit und hat die Datei nicht "geschlossen". – zerkms

+0

Ja, aber ich nehme an, dass 'autoClose' nicht ohne Grund auf' false' gesetzt wurde - genau wie asing 'fs.open' zuerst, anstatt den Dateipfad zu' fs.createReadStream' zu übergeben, wie in Frage erklärt: "Hinweis Ich weiß, ich könnte das ohne fd machen, aber das ist eine Vereinfachung von komplexem Code. " – ahwayakchih

+0

Ja, das verstehe ich auch. Aber in diesem Fall führte die zu starke Vereinfachung zu den naiv erwarteten Ergebnissen, die keine Bestätigung brauchten :-) Wie auch immer, ich beziehe mich nicht auf deine Antwort, es ist gut und ich habe es aufgewertet :-) – zerkms