2017-08-30 1 views
0

J'utilise Observable (Rxhttp en particulier). J'utilise également connect-timeout pour des demandes de longue durée. Malheureusement, mon .subscribe semble toujours fonctionner, même lorsque le middleware de gestion des erreurs a été touché, et aurait dû fermer la connexion.Utilisation d'observables dans le routage express Le middleware provoque le paramétrage des en-têtes après leur envoi.

Il en résulte souvent un: Error: Can't set headers after they are sent.

Un cas reproductible minimale est inférieure.

'use strict' 

const express = require('express') 
const timeout = require('connect-timeout') 
const Rx = require('rx') 
const http = require('http') 

let app = express() 
app.use(timeout('1s')) 

app.get('/', (req, res) => { 
    //in the real application the Rx is an external request 
    return Rx.Observable.create((observer) => { 
    observer.onNext({ 
     response: 'potato' 
    }) 
    observer.onCompleted() 
    }) 
    .delay(new Date(Date.now() + 1500)) 
    .subscribe((x) => { 
    console.log('this runs') 
    res.status(200).send() 
    }, (e) => { 
    console.log('this does not') 
    }) 
}) 

app.use((err, req, res, next) => { 
    if(err) { 
    res.status(500).send('SOMETHING BROKE!') 
    } 
}) 

const httpServer = http.createServer(app) 
httpServer.listen(3000, function() { 
    console.log('Listening on port %d.', 3000) 
}) 

Comment éviter ce problème? Pourquoi le .subscribe est-il toujours en cours d'exécution même si le middleware a expiré? Je sais que je peux éviter cela en enchaînant un .timeout sur l'observable, mais cela a l'inconvénient qu'il ne correspond pas nécessairement au délai d'attente de connexion (par exemple, une lecture de base de données aurait pu se produire, la demande globale aurait pu prendre plus d'un en second lieu, alors que l'observable lui-même ne le fait pas). Existe-t-il une solution plus générique?

Répondre

0

Connection-timeout npm fonctionne comme ceci. La fonction retarde les réponses autant de millisecondes que vous l'avez indiqué. Dans ce cas, les réponses sont retardées de 1,5 seconde. Donc, le client n'obtiendra pas la réponse jusqu'à ce que 1,5 secondes passent. La fonction vérifie si la réponse a été envoyée après 1 seconde la demande a été reçue, dans ce cas, les réponses ne sont pas envoyées avant 1,5 secondes, donc elle renvoie une erreur même si la réponse est envoyée plus tard.

Mon code, mon serveur vérifie 5 secondes plus tard si la réponse a été envoyée, sinon elle renvoie une erreur.

'use strict' 

const express = require('express') 
const timeout = require('connect-timeout') 
const Rx = require('rx') 
const http = require('http') 

let app = express() 
app.use(timeout('5s')); // if can't send the response in 5 seconds, it will return request timeout error 

app.get('/', (req, res) => { 
    //in the real application the Rx is an external request 
    Rx.Observable.create((observer) => { 
    observer.onNext({ 
     response: 'potato' 
    }) 
    observer.onCompleted() 
    }) 
    .delay(new Date(Date.now() + 1000)) // I am delaying the requests 1 seconds 
    .subscribe((x) => { 
    console.log(x); 
    console.log('this runs') 
    res.status(200).send() 
    }, (e) => { 
    console.log('this does not') 
    }) 
}) 

app.use((err, req, res, next) => { 
    if(err) { 
    console.log(err); 
    res.status(500).send('SOMETHING BROKE!') 
    } 
}) 

const httpServer = http.createServer(app) 
httpServer.listen(3000, function() { 
    console.log('Listening on port %d.', 3000) 
}) 

donc mes réponses du serveur seront envoyés une seconde après réception de la demande et le serveur va vérifier pour voir si elle a été envoyée 5 secondes plus tard, si elle ne l'était pas renverront Service Unavailable: Request Timeout.

+0

Je suis désolé je n'ai pas été clair, mon retard simule délibérément le cas de minutage, mais l'abonnement fonctionne encore ... –

+0

C'est parce que subscribe est censé fonctionner après le délai, son gestionnaire d'erreur ne l'est pas. @AbrahamP – turmuka