2015-09-15 16 views
13

L'API la mia webapp sta parlando a volte sovraccarichi e sta inviando 500 Internal Server Error se non è in grado di gestire la richiesta.

Ci sono oltre 100 richieste diverse che la mia applicazione Web può inviare, quindi se implemento un nuovo tentativo su ciascuna di esse, mi costerà ore di digitazione.

sto già usando $ httpProvider intercettore, qui è (semplificato)

$httpProvider.interceptors.push(function ($q) { 
    return { 
     responseError: function (response) { 
      switch (response.status) { 
       case 401 : 
        window.location = "/"; 
        alert('Session has expired. Redirecting to login page'); 
        break; 
       case 500 : 
        // TODO: retry the request 
        break; 
      } 
      return $q.reject(response); 
     } 
    }; 
}); 

Come potrei inviare nuovamente una richiesta dopo aver ottenuto il codice 500 risposta dal server?

+0

Anche la connessione Internet persa può essere gestita (stato HTTP 0). Vuoi che lo aggiunga nella risposta? –

+0

puoi dirci come possiamo aiutarti a risolvere la domanda se non sei soddisfatto delle risposte? Se è già stato risolto con l'aiuto delle risposte, sarebbe opportuno gestire la taglia in modo appropriato o se lo risolvessi da solo sarebbe bene fornire la soluzione. Grazie. –

risposta

17

angolare fornisce riferimento all'oggetto di configurazione, che è stato utilizzato da $ http servizio per fare la richiesta nella risposta (response.config). Ciò significa che se siamo in grado di iniettare il servizio $ http nell'intercettore, possiamo facilmente inviare nuovamente la richiesta. L'iniezione semplice del servizio $ http nell'intercettore non è possibile a causa della dipendenza circolare ma fortunatamente esiste una soluzione alternativa.

Questo è un esempio di come è possibile implementare un intercettatore di questo tipo.

$httpProvider.interceptors.push(function ($q, $injector) { 
    var incrementalTimeout = 1000; 

    function retryRequest (httpConfig) { 
     var $timeout = $injector.get('$timeout'); 
     var thisTimeout = incrementalTimeout; 
     incrementalTimeout *= 2; 
     return $timeout(function() { 
      var $http = $injector.get('$http'); 
      return $http(httpConfig); 
     }, thisTimeout); 
    }; 

    return { 
     responseError: function (response) { 
      if (response.status === 500) { 
       if (incrementalTimeout < 5000) { 
        return retryRequest(response.config); 
       } 
       else { 
        alert('The remote server seems to be busy at the moment. Please try again in 5 minutes'); 
       } 
      } 
      else { 
       incrementalTimeout = 1000; 
      } 
      return $q.reject(response); 
     } 
    }; 
}); 

Nota: In questo esempio di implementazione l'intercettore ritenterà la richiesta fino a quando si riceve una risposta con stato che è diverso da quello . Il miglioramento di questo può aggiungere un po 'di timeout prima di riprovare e riprovare solo una volta.

+1

Puoi fornire maggiori informazioni sul motivo per cui non funziona? –

+0

il motivo della richiesta non riesce è sovraccarico del server. Il server restituisce 504 risposte se la coda è troppo grande o sta esaurendo la memoria – Dan

+0

IMHO dovresti affrontare questo problema dal lato server. Se non riesci a farlo a causa di alcuni motivi, il meglio che puoi fare è aggiungere il timeout prima di riprovare e sperare che alla successiva richiesta il server sia disponibile. –

3

È possibile verificare eventuali errori del lato server espandendo il controllo del codice di stato un po 'di più. Questo intercettore tenterà di riprovare la richiesta più volte e lo farà su qualsiasi codice di risposta 500 o superiore. Attenderà 1 secondo prima di riprovare e si arrenderà dopo 3 tentativi.

$httpProvider.interceptors.push(function ($q, $injector) { 

    var retries = 0, 
     waitBetweenErrors = 1000, 
     maxRetries = 3; 

    function onResponseError(httpConfig) { 
     var $http = $injector.get('$http'); 
     setTimeout(function() { 
      return $http(httpConfig); 
     }, waitBetweenErrors); 
    } 

    return { 
     responseError: function (response) { 
      if (response.status >= 500 && retries < maxRetries) { 
       retries++; 
       return onResponseError(response.config); 
      } 
      retries = 0; 
      return $q.reject(response); 
     } 
    }; 
}); 
+2

Sono un principiante angolare, ma mi sembra che qui debba essere utilizzato il timeout $ invece di setTimeout, allo scopo di convogliare lo stato della promessa $ http appena creata nella promessa fallita '$ http' . In altre parole, la promessa che ha creato 500 richieste continua a vivere e dovrebbe attivare la callback 'success' se il tentativo ha esito positivo. – Dan

+0

@Dan Hai ragione ... 'setTimeout' ingoia un errore di risposta e la funzione success della richiesta originale viene chiamata con dati indefiniti dopo che tutti i tentativi non sono riusciti. Piping the state propaga 'success' o' error'. – builder

+2

Inoltre, se non sbaglio, i tentativi sono condivisi per ogni richiesta, quindi se più richieste fallirebbero allo stesso tempo, questa soluzione non funzionerà. –

Problemi correlati