J'obtiens "Réponse d'échec HTTP pour (URL inconnue): 0 Erreur inconnue" au lieu du message d'erreur réel dans Angular

121

J'utilise Angular 4 HttpClientpour envoyer des demandes à un service externe. C'est une configuration très standard:

this.httpClient.get(url).subscribe(response => {
  //do something with response
}, err => {
  console.log(err.message);
}, () => {
  console.log('completed');
}

Le problème est que lorsque la demande échoue, je vois un Http failure response for (unknown url): 0 Unknown Errormessage générique dans la console. Pendant ce temps, lorsque j'inspecte la demande ayant échoué dans Chrome, je peux voir que l'état de la réponse est 422, et dans l'onglet "Aperçu", je vois le message réel décrivant la cause de l'échec.

Comment accéder au message de réponse réel que je peux voir dans les outils de développement Chrome?

Voici une capture d'écran illustrant le problème: entrez la description de l'image ici

grdl
la source
essayez d'enregistrer l' errobjet entier - pas seulement lemessage
Pavel Agarkov
Je suis confronté au même problème et j'allais créer une question pour cela aussi, voici l'objet err complet: gist.github.com/GO3LIN/7cffc3b0aa1f24d3e23e28cc907237fc
Mehdi Benmoha
1
Ou mieux {"headers": {"normalizedNames": {}, "lazyUpdate": null, "headers": {}}, "status": 0, "statusText": "Unknown Error", "url": null, "ok": false, "name": "HttpErrorResponse", "message": "Réponse d'échec HTTP pour (URL inconnue): 0 Erreur inconnue", "error": {"isTrusted": true}}
Mehdi Benmoha
@PavelAgarkov, il ne s'agit pas de journaliser uniquement le message. Le HttpErrorResponse que je reçois ne contient tout simplement pas le message d'erreur réel. Voici une capture d' écran du problème. Vous pouvez voir ici que l'erreur que j'enregistre a un message disant "... erreur inconnue ..." mais lorsque vous regardez l'aperçu de la réponse à la demande ci-dessus, vous pouvez voir le message réel et significatif.
grdl
Utilisez-vous un technicien de service?
Mackelito

Réponses:

96

Le problème était lié à CORS . J'ai remarqué qu'il y avait une autre erreur dans la console Chrome:

Aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L' accès à l' origine ' http: // localhost: 4200 ' n'est donc pas autorisé. La réponse avait le code d'état HTTP 422. »

Cela signifie que la réponse du serveur principal manquait d'en- Access-Control-Allow-Origintête même si le backend nginx était configuré pour ajouter ces en-têtes aux réponses avec la add_headerdirective .

Cependant, cette directive n'ajoute des en-têtes que lorsque le code de réponse est 20X ou 30X. Sur les réponses d'erreur, les en-têtes étaient manquants. J'avais besoin d'utiliser un alwaysparamètre pour m'assurer que l'en-tête est ajouté quel que soit le code de réponse:

add_header 'Access-Control-Allow-Origin' 'http://localhost:4200' always;

Une fois le backend correctement configuré, je pouvais accéder au message d'erreur réel dans le code angulaire.

grdl
la source
le lien suivant peut également être utile pour activer CORS
Bobs
11
où ajouter cette ligne?
Omid Ataollahi
1
comment ajouter «toujours» à une fonction .use express.js? Typiquement, la structure est: app.use (function (req, res, next) {res.header ("Access-Control-Allow-Origin", " localhost: 4200" );…}); Comme vous pouvez le voir, l'en-tête res.header autorise deux paramètres ... une chaîne de contrôle et une valeur. J'ai essayé d'ajouter «toujours» de diverses manières, mais elles semblent toutes échouer. Aucune suggestion?
AppDreamer
@grdl, où la ligne add_header doit être ajoutée?
sattva_venu le
où ajouter cette ligne? J'utilise php pour mon api
Mustafa UYSAL
19

Au cas où quelqu'un d'autre finirait aussi perdu que moi ... Mes problèmes n'étaient PAS dus à CORS (j'ai le contrôle total du (des) serveur (s) et CORS a été configuré correctement!).

Mon problème était dû au fait que j'utilise le niveau de la plate-forme Android 28 qui désactive les communications réseau en texte clair par défaut et que j'essayais de développer l'application qui pointe vers l'adresse IP de mon ordinateur portable (qui exécute le serveur API). L'URL de base de l'API ressemble à http: // [LAPTOP_IP]: 8081 . Comme ce n'est pas https , Android Webview bloque complètement le xfer réseau entre le téléphone / émulateur et le serveur de mon ordinateur portable. Afin de résoudre ce problème:

Ajouter une configuration de sécurité réseau

Nouveau fichier dans le projet: resources / android / xml / network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <!-- Set application-wide security config -->
  <base-config cleartextTrafficPermitted="true"/>
</network-security-config>

REMARQUE: cela doit être utilisé avec précaution car il autorisera tous les textes en clair de votre application (rien n'est obligé d'utiliser https). Vous pouvez le restreindre davantage si vous le souhaitez.

Référencez la configuration dans le fichier main config.xml

<platform name="android">
    ...
    <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
        <application android:networkSecurityConfig="@xml/network_security_config" />
    </edit-config>
    <resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" />
    ....
</platform>

C'est tout! À partir de là, j'ai reconstruit l'APK et l'application était maintenant capable de communiquer à la fois à partir de l'émulateur et du téléphone.

Plus d'informations sur le réseau sec: https://developer.android.com/training/articles/security-config.html#CleartextTrafficPermitted

haggy
la source
Merci beaucoup! J'utilisais également une URL "http". Je l'ai changé en "https" et cela a fonctionné. Btw, changer simplement une URL en https ne fonctionnera pas, vous avez besoin d'un certificat pour gérer cela. Le serveur que j'utilisais prend en charge les deux, donc c'était plus facile pour moi. Quoi qu'il en soit, merci une tonne!
Xonshiz
1
oui ... pour moi il est à propos de trop .... parce texte clair que je utilise http.. il ne serait problème si je l' utilise https.... mais si je veux continuer à utiliser http, j'ajouter directement android:usesCleartextTraffic="true"dans applicationtag AndroidManifest.xml. ..et ça marche .... merci pour la mention sur cleartext...
Syamsoul Azrien
Comment puis-je activer cela dans Spring Boot? Je suis désolé si la question est trop triviale mais je suis un débutant et je ne trouve aucune solution en ligne
Asma Rahim Ali Jafri
13

travaille pour moi après avoir désactivé l'extension de blocage des publicités dans Chrome, cette erreur apparaît parfois parce que quelque chose qui bloque http dans le navigateur

entrez la description de l'image ici

Dwi Yanuar Ilham
la source
1
pour moi, c'était uBlock Origin qui a bloqué le téléchargement du fichier avec `` analytics '' dans son nom
marke
9

Si vous utilisez l'application .NET Core, cette solution peut vous aider!

De plus, cela peut ne pas être une erreur de demande angulaire ou autre dans votre application frontale

Tout d'abord, vous devez ajouter le package Microsoft CORS Nuget:

Install-Package Microsoft.AspNetCore.Cors

Vous devez ensuite ajouter les services CORS dans votre startup.cs. Dans votre méthode ConfigureServices, vous devriez avoir quelque chose de similaire à ce qui suit:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
}

Ensuite, ajoutez le middleware CORS à votre application. Dans votre startup.cs, vous devriez avoir une méthode Configure. Vous devez l'avoir semblable à ceci:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
    app.UseCors( options => 
    options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    app.UseMvc();
}

Les options lambda sont une API fluide afin que vous puissiez ajouter / supprimer toutes les options supplémentaires dont vous avez besoin. Vous pouvez en fait utiliser l'option «AllowAnyOrigin» pour accepter n'importe quel domaine, mais je vous recommande fortement de ne pas le faire car cela ouvre des appels d'origine croisée de n'importe qui. Vous pouvez également limiter les appels d'origine croisée à leur méthode HTTP (GET / PUT / POST, etc.), de sorte que vous ne pouvez exposer que les appels GET entre domaines, etc.

sathish
la source
5

Cette erreur se produisait pour moi dans Firefox mais pas dans Chrome lors du développement local, et elle s'est avérée être due au fait que Firefox ne faisait pas confiance au certificat SSL de mon API locale (ce qui n'est pas valide, mais je l'avais ajouté à mon magasin de certificats local, ce qui laisse chrome lui fait confiance mais pas ff). La navigation vers l'API directement et l'ajout d'une exception dans Firefox ont résolu le problème.

frax
la source
1
J'ai parcouru plusieurs réponses CORS et l'une après l'autre, chacune n'a pas fourni de solution lors de l'utilisation de Firefox. J'ai regardé ce post et j'ai pensé, "pas question que ce soit ça mais je suis à court d'idées" et bien sûr cela a fonctionné. Merci beaucoup!
Aaron Jordan
@frax, j'ai eu exactement le même cas! Merci! :)
W92
5

Pour moi, cela a été causé par une exception JsonSerializerException côté serveur.

Une exception non gérée s'est produite lors de l'exécution de la requête Newtonsoft.Json.JsonSerializationException: Boucle d'auto-référencement détectée avec le type ...

Le client a dit:

POST http://localhost:61495/api/Action net::ERR_INCOMPLETE_CHUNKED_ENCODING
ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: null, ok: false, …}

Simplifier le type de réponse en éliminant les boucles a résolu le problème.

Perrier
la source
2

Si vous utilisez Laravel comme backend, modifiez votre fichier .htaccess en collant simplement ce code, pour résoudre le problème CROS dans votre projet Angular ou IONIC

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
Shirjeel Khan
la source
6
Vous ne devriez jamais autoriser "*"! En général, vous savez qui parle à votre backend et vous devez définir leur hôte explicitement.
itmuckel
@itmuckel mais si vous faites une application pour Android, l'hôte n'est pas connu. Est-ce que chaque mobile consommera votre service, ai-je raison?
Martin
2
nous devions utiliser cordova-plugin-advanced-http et le wrapper @ ionic / native pour avoir des appels http depuis le périphérique de manière native au lieu d'utiliser un appel ajax basé sur un navigateur. @Martin
user323774
2

Une erreur similaire peut se produire lorsque vous n'avez pas fourni de certificat client valide et de jeton que votre serveur comprend:

Erreur:

Réponse d'échec HTTP pour (URL inconnue): 0 Erreur inconnue

Exemple de code:

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

class MyCls1 {

  constructor(private http: HttpClient) {
  }

  public myFunc(): void {

    let http: HttpClient;

    http.get(
      'https://www.example.com/mypage',
      {
        headers:
          new HttpHeaders(
            {
              'Content-Type': 'application/json',
              'X-Requested-With': 'XMLHttpRequest',
              'MyClientCert': '',        // This is empty
              'MyToken': ''              // This is empty
            }
          )
      }
    ).pipe( map(res => res), catchError(err => throwError(err)) );
  }

}

Notez que les deux MyClientCert& MyTokensont des chaînes vides, d'où l'erreur.
MyClientCert& MyTokenpeut être n'importe quel nom que votre serveur comprend.

Manohar Reddy Poreddy
la source
J'utilise ce code dans mon application ionique. mon application ionique utilisée comme index sur mon site. mais ces astuces ne peuvent pas m'aider. semble que mes apis dans laravel nécessitent une configuration peut-être dans ngnix ou laravel ou mon hôte docker ... j'ai utilisé le middleware cors pour cors activé et cela a fonctionné sur mon local avec http mais lorsqu'il est déployé sur docker, je ne peux pas appeler mon api avec https
sabre tabatabaee yazdi
lorsque j'appelle mes apis de repos à partir de http, ceux-ci ont fonctionné, mais lorsque j'appelle https, ils n'ont pas répondu à mes clients. et renvoyer une erreur de type mixte. Je pense qu'il y a une erreur de certificat ou quelque chose comme la configuration de nginx ou .htaccess parce que j'ajoute un middleware cors pour les cors et tout a bien fonctionné sans https. mon client hébergé sur le résultat http appel http est ok. mais quand mon client héberge sur https et appelle des erreurs https se sont produites
sabre tabatabaee yazdi
Ok, une solution est, allez à l'url https: // que vous avez, et cliquez sur l'icône de verrouillage à côté du https, téléchargez le certificat dans un fichier, lisez ce fichier via import / require / fs, puis donnez / passez cela chaîne de certificat à l'appel à l'url, alors cela fonctionnera.
Manohar Reddy Poreddy
2

J'utilise les extensions ASP.NET SPA qui me créent un proxy sur les ports 5000 et 5001 qui passent par le port 4200 d'Angular pendant le développement.

J'avais configuré CORS correctement pour le port https 5001 et tout allait bien, mais je suis allé par inadvertance à un vieux signet qui était pour le port 5000. Puis soudainement, ce message est apparu. Comme d'autres l'ont dit dans la console, il y avait un message d'erreur «Preflight».

Ainsi, quel que soit votre environnement, si vous utilisez CORS, assurez-vous que tous les ports sont spécifiés - car l'hôte et le port comptent tous deux.

Simon_Weaver
la source
2

Je recevais ce message exact chaque fois que mes demandes prenaient plus de 2 minutes pour se terminer. Le navigateur se déconnecterait de la demande, mais la demande sur le backend se poursuivait jusqu'à ce qu'elle soit terminée. Le serveur (API Web ASP.NET dans mon cas) ne détecte pas la déconnexion.

Après une journée entière de recherche, j'ai finalement trouvé cette réponse , expliquant que si vous utilisez la configuration proxy , elle a un délai d'expiration par défaut de 120 secondes (ou 2 minutes).

Ainsi, vous pouvez modifier votre configuration de proxy et la définir comme vous le souhaitez:

{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false,
    "timeout": 6000000
  }
}

Maintenant, j'utilisais agentkeepalive pour le faire fonctionner avec l'authentification NTLM , et je ne savais pas que le délai d'expiration de l'agent n'a rien à voir avec le délai d'expiration du proxy, donc les deux doivent être définis. Il m'a fallu un certain temps pour m'en rendre compte, alors voici un exemple:

const Agent = require('agentkeepalive');

module.exports = {
    '/api/': {
        target: 'http://localhost:3000',
        secure: false,
        timeout: 6000000,          // <-- this is needed as well
        agent: new Agent({
            maxSockets: 100,
            keepAlive: true,
            maxFreeSockets: 10,
            keepAliveMsecs: 100000,
            timeout: 6000000,      // <-- this is for the agentkeepalive
            freeSocketTimeout: 90000
        }),
        onProxyRes: proxyRes => {
            let key = 'www-authenticate';
            proxyRes.headers[key] = proxyRes.headers[key] &&
                proxyRes.headers[key].split(',');
        }
    }
};
Marcos Dimitrio
la source
2

Pour moi, c'était un problème de navigateur, car mes demandes fonctionnaient bien dans Postman.

Il s'avère que pour une raison quelconque, Firefox et Chrome ont bloqué les demandes allant au port 6000, une fois que j'ai changé le port de l'API ASP.NET en 4000, l'erreur s'est transformée en une erreur CORS connue que je pouvais corriger.

Chrome m'a au moins montré ce ERR_UNSAFE_PORTqui m'a donné un indice sur ce qui pouvait ne pas être le cas.

Shahin Dohan
la source
1

Si vous avez un en-tête cors approprié en place. Votre réseau d'entreprise supprime peut-être l'en-tête cors. Si le site Web est accessible de l'extérieur, essayez d'y accéder depuis l'extérieur de votre réseau pour vérifier si le réseau est à l'origine du problème - une bonne idée quelle qu'en soit la cause.

N-mangé
la source
1

Dans asp.net core, si votre contrôleur api n'a pas d'annotation appelée [AllowAnonymous], ajoutez-la au-dessus du nom de votre contrôleur comme

[ApiController]
    [Route("api/")]
    [AllowAnonymous]
    public class TestController : ControllerBase
dgncn
la source
0

N'est pas aussi vieux que d'autres questions, mais je me suis juste battu avec cela dans une application Ionic-Laravel, et rien ne fonctionne à partir d'ici (et d'autres messages), j'ai donc installé https://github.com/barryvdh/laravel-cors complément dans Laravel et a commencé et ça marche plutôt bien.

gersonmontenegro
la source
0

Le mien a été causé par une relation invalide dans les modèles que j'essayais d'interroger. Compris en déboguant la réponse, il s'est écrasé au niveau de la relation.

J.Kirk.
la source
0

Pour moi, ce n'était pas un problème angulaire. Était un champ de type DateTime dans la base de données qui a une valeur de (0000-00-00) et mon modèle ne peut pas lier cette propriété correctement, j'ai donc changé pour une valeur valide comme (2019-08-12).

J'utilise .net core, OData v4 et MySql (connecteur EF pomelo)

Luis Lopez
la source
0

Ajoutez ces codes dans votre fichier de connexion

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: PUT,GET,POST,DELETE");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
Abdelhakim Ezzahraoui
la source
0

S'il s'agit d'un service de nœud, essayez les étapes décrites ici

Fondamentalement, il s'agit d'une erreur CORS (Cross-Origin Resource Sharing). Plus d'informations sur ces erreurs ici .

Une fois que j'ai mis à jour mon service de nœud avec les lignes suivantes, cela a fonctionné:

let express = require("express");
let app = express();

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");    
    next();
  });
FistOfFury
la source
-2

Mon erreur était que le fichier était trop volumineux (le noyau dotnet semble avoir une limite @ ~ 25 Mo). Réglage

  • maxAllowedContentLength à 4294967295 (valeur maximale de uint) dans web.config
  • décoration de l'action du contrôleur avec [DisableRequestSizeLimit]
  • services.Configure (options => {options.MultipartBodyLengthLimit = 4294967295;}); dans Startup.cs

résolu le problème pour moi.

Spikolynn
la source