Recibo "Respuesta de falla de Http para (URL desconocida): 0 Error desconocido" en lugar del mensaje de error real en Angular

121

Estoy usando Angular 4 HttpClientpara enviar solicitudes a un servicio externo. Es una configuración muy estándar:

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

El problema es que, cuando falla la solicitud, veo un Http failure response for (unknown url): 0 Unknown Errormensaje genérico en la consola. Mientras tanto, cuando inspecciono la solicitud fallida en Chrome, puedo ver que el estado de la respuesta es 422, y en la pestaña "vista previa" veo el mensaje real que describe la causa del error.

¿Cómo accedo al mensaje de respuesta real que puedo ver en las herramientas de desarrollo de Chrome?

Aquí hay una captura de pantalla que demuestra el problema: ingrese la descripción de la imagen aquí

grdl
fuente
intente registrar el errobjeto completo , no solo elmessage
Pavel Agarkov
Estoy enfrentando el mismo problema e iba a crear una pregunta para esto también, aquí está el objeto de error completo: gist.github.com/GO3LIN/7cffc3b0aa1f24d3e23e28cc907237fc
Mehdi Benmoha
1
O mejor {"headers": {"normalizedNames": {}, "lazyUpdate": null, "headers": {}}, "status": 0, "statusText": "Error desconocido", "url": null, "ok": falso, "nombre": "HttpErrorResponse", "mensaje": "Respuesta de error de Http para (URL desconocida): 0 Error desconocido", "error": {"isTrusted": true}}
Mehdi Benmoha
@PavelAgarkov, no se trata de registrar solo mensajes. El HttpErrorResponse que recibo simplemente no contiene el mensaje de error real. Aquí tienes una captura de pantalla del problema. Allí puede ver que el error que registro tiene un mensaje que dice "... error desconocido ..." pero cuando mira la vista previa de la respuesta de solicitud arriba, puede ver el mensaje real y significativo.
Grdl
¿Utiliza un trabajador de servicios?
Mackelito

Respuestas:

96

El problema estaba relacionado con CORS . Noté que había otro error en la consola de Chrome:

No hay ningún encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, no se permite el acceso al origen ' http: // localhost: 4200 '. La respuesta tenía el código de estado HTTP 422.

Esto significa que a la respuesta del servidor backend le faltaba el Access-Control-Allow-Originencabezado aunque el backend nginx estaba configurado para agregar esos encabezados a las respuestas con la add_headerdirectiva .

Sin embargo, esta directiva solo agrega encabezados cuando el código de respuesta es 20X o 30X. En las respuestas de error faltaban los encabezados. Necesitaba usar el alwaysparámetro para asegurarme de que se agregue el encabezado independientemente del código de respuesta:

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

Una vez que el backend se configuró correctamente, pude acceder al mensaje de error real en el código angular.

grdl
fuente
También el siguiente enlace puede ser útil para habilitar CORS: docs.microsoft.com/en-us/aspnet/web-api/overview/security/…
Bobs
11
¿Dónde debería agregarse esta línea?
Omid Ataollahi
1
¿Cómo se agrega 'siempre' a una función express.js .use? Normalmente, la estructura es: app.use (function (req, res, next) {res.header ("Access-Control-Allow-Origin", " localhost: 4200" );…}); Como puede ver, res.header permite dos parámetros ... una cadena de control y un valor. He intentado agregar "siempre" de varias maneras, pero todas parecen fallar. ¿Alguna sugerencia?
AppDreamer
@grdl, ¿dónde se debe agregar la línea add_header?
sattva_venu
¿Dónde agregar esta línea? Uso php para mi api
Mustafa UYSAL
19

En caso de que alguien más termine tan perdido como yo ... Mis problemas NO se debieron a CORS (¡tengo el control total de los servidores y CORS se configuró correctamente!).

Mi problema fue porque estoy usando el nivel 28 de la plataforma Android que deshabilita las comunicaciones de red de texto sin formato de forma predeterminada y estaba tratando de desarrollar la aplicación que apunta a la IP de mi computadora portátil (que ejecuta el servidor API). La URL base de la API es algo así como http: // [LAPTOP_IP]: 8081 . Como no es https , la vista web de Android bloquea completamente la transferencia de red entre el teléfono / emulador y el servidor de mi computadora portátil. Para arreglar esto:

Agregar una configuración de seguridad de red

Nuevo archivo en el proyecto: 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>

NOTA: Esto debe usarse con cuidado ya que permitirá todo el texto sin cifrar de su aplicación (nada forzado a usar https). Puede restringirlo más si lo desea.

Haga referencia a la configuración en config.xml principal

<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>

¡Eso es! A partir de ahí, reconstruí el APK y la aplicación ahora podía comunicarse tanto desde el emulador como desde el teléfono.

Más información sobre la red sec: https://developer.android.com/training/articles/security-config.html#CleartextTrafficPermitted

haggy
fuente
¡Muchas gracias! También estaba usando una URL "http". Lo cambié a "https" y funcionó. Por cierto, simplemente cambiar una URL a https no funcionará, necesita un certificado para manejar eso. El servidor que estaba usando admite ambos, por lo que fue más fácil para mí. De todos modos, ¡muchas gracias!
Xonshiz
1
sí ... para mí se trata de texto claro también .... porque yo estoy usando http.. sería no será un problema si uso https.... pero en caso de que aún desea utilizar http, i añadir directamente android:usesCleartextTraffic="true"en applicationla etiqueta en AndroidManifest.xml. ..y está funcionando .... gracias por mencionar sobre cleartext...
Syamsoul Azrien
¿Cómo puedo habilitar esto en Spring Boot? Lo siento si la pregunta es demasiado trivial, pero soy un principiante y no puedo encontrar ninguna solución en línea
Asma Rahim Ali Jafri
13

trabajando para mí después de desactivar la extensión de bloqueo de anuncios en Chrome, este error aparece en algún momento porque algo que bloquea http en el navegador

ingrese la descripción de la imagen aquí

Dwi Yanuar Ilham
fuente
1
para mí fue uBlock Origin que bloqueó la descarga de archivos con 'análisis' en su nombre
marke
9

Si está utilizando la aplicación .NET Core, ¡esta solución podría ayudar!

Además, esto podría no ser un error de solicitud angular u otro en su aplicación frontal

Primero, debe agregar el paquete Microsoft CORS Nuget:

Install-Package Microsoft.AspNetCore.Cors

Luego, debe agregar los servicios CORS en su startup.cs. En su método ConfigureServices debería tener algo similar a lo siguiente:

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

A continuación, agregue el middleware CORS a su aplicación. En su startup.cs debe tener un método Configure. Necesitas tenerlo similar a esto:

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

Las opciones lambda son una API fluida, por lo que puede agregar / eliminar cualquier opción adicional que necesite. De hecho, puede usar la opción "AllowAnyOrigin" para aceptar cualquier dominio, pero le recomiendo que no lo haga, ya que abre llamadas de origen cruzado de cualquier persona. También puede limitar las llamadas de origen cruzado a su método HTTP (GET / PUT / POST, etc.), por lo que solo puede exponer llamadas GET entre dominios, etc.

sathish
fuente
5

Este error me estaba ocurriendo en Firefox pero no en Chrome mientras desarrollaba localmente, y resultó ser causado por Firefox no confiando en el certificado ssl de mi API local (que no es válido, pero lo había agregado a mi tienda de certificados local, lo que permitió Chrome confía en él pero no en ff). Navegar a la API directamente y agregar una excepción en Firefox solucionó el problema.

frax
fuente
1
He pasado por varias respuestas CORS y una tras otra, cada una no proporcionó una solución al usar Firefox. Miré esta publicación y pensé, "de ninguna manera, pero no tengo ideas, qué demonios" y, efectivamente, funcionó. Muchas gracias!
Aaron Jordan
@frax, ¡tuve exactamente el mismo caso! ¡Gracias! :)
W92
5

Para mí, fue causado por una excepción JsonSerializerException del lado del servidor.

Se ha producido una excepción no controlada al ejecutar la solicitud Newtonsoft.Json.JsonSerializationException: bucle de autorreferencia detectado con el tipo ...

El cliente dijo:

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

Simplificar el tipo de respuesta al eliminar los bucles resolvió el problema.

Perrier
fuente
2

Si está utilizando Laravel como su Backend, edite su archivo .htaccess simplemente pegando este código, para resolver el problema CROS en su proyecto Angular o IONIC

Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
shirjeel khan
fuente
6
¡Nunca debería permitir "*"! En general, sabes quién está hablando con tu backend y debes configurar su host explícitamente.
itmuckel
@itmuckel, pero si está haciendo una aplicación para Android, no se conoce el host. Serán todos los móviles los que consuman tu servicio, ¿verdad?
Martin
2
necesitábamos usar cordova-plugin-advanced-http y el contenedor @ ionic / native para tener llamadas http desde el dispositivo de forma nativa en lugar de usar una llamada ajax basada en navegador. @Martin
user323774
2

Puede ocurrir un error similar cuando no proporcionó un certificado de cliente válido y un token que su servidor comprenda:

Error:

Respuesta de error de HTTP para (URL desconocida): 0 Error desconocido

Código de ejemplo:

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)) );
  }

}

Tenga en cuenta que ambos MyClientCert& MyTokenson cadenas vacías, de ahí el error.
MyClientCert& MyTokenpuede ser cualquier nombre que comprenda su servidor.

Manohar Reddy Poreddy
fuente
Yo uso este código en mi aplicación iónica. mi aplicación iónica utilizada como índice en mi sitio. pero estos trucos no pueden ayudarme. parece que mi apis en laravel necesita configuración tal vez en ngnix o laravel o mi host de docker ... usé middleware cors para cors habilitado y funcionó en mi local con http pero cuando se implementó en docker no puedo llamar a mi api con https
saber tabatabaee yazdi
cuando llamo a mis apis de descanso desde http, esas funcionaron pero cuando llamé a https no respondieron a mis clientes. y devuelve el error de tipo mixto. Creo que hay un error de certificado o algo como la configuración de nginx o .htaccess porque agregué el middleware de cors para cors y todo funcionó bien sin https. mi cliente alojado en http llamada http resultado está bien. pero cuando mi cliente host en https y llama a https se
produjeron
Ok, una solución es ir a la URL https: // que tienes y hacer clic en el ícono de candado al lado de https, descargar el certificado a un archivo, leer ese archivo a través de import / require / fs, luego dar / pasar ese cadena de certificado a la llamada a la URL, entonces funcionará.
Manohar Reddy Poreddy
2

Estoy usando ASP.NET SPA Extensions que me crea un proxy en los puertos 5000 y 5001 que pasan al puerto 4200 de Angular durante el desarrollo.

Había configurado CORS correctamente para el puerto https 5001 y todo estaba bien, pero sin darme cuenta fui a un marcador antiguo que era para el puerto 5000. Entonces, de repente, apareció este mensaje. Como han dicho otros en la consola, había un mensaje de error de "verificación previa".

Por lo tanto, independientemente de su entorno, si está utilizando CORS, asegúrese de tener todos los puertos especificados, ya que el host y el puerto son importantes.

Simon_Weaver
fuente
2

Recibía ese mensaje exacto cada vez que mis solicitudes tardaban más de 2 minutos en completarse. El navegador se desconectaría de la solicitud, pero la solicitud en el backend continuó hasta que finalizó. El servidor (ASP.NET Web API en mi caso) no detectaría la desconexión.

Después de un día entero de búsqueda, finalmente encontré esta respuesta , explicando que si usa la configuración de proxy , tiene un tiempo de espera predeterminado de 120 segundos (o 2 minutos).

Por lo tanto, puede editar la configuración de su proxy y configurarla para lo que necesite:

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

Ahora, estaba usando agentkeepalive para que funcione con la autenticación NTLM y no sabía que el tiempo de espera del agente no tiene nada que ver con el tiempo de espera del proxy, por lo que ambos deben configurarse. Me tomó un tiempo darme cuenta de eso, así que aquí hay un ejemplo:

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
fuente
2

Para mí, era un problema del navegador, ya que mis solicitudes funcionaban bien en Postman.

Resulta que, por alguna razón, Firefox y Chrome bloquearon las solicitudes que iban al puerto 6000, una vez que cambié el puerto de la API ASP.NET a4000 , el error cambió a un error CORS conocido que pude corregir.

Chrome al menos me mostró lo ERR_UNSAFE_PORTque me dio una pista sobre lo que podría estar mal.

Shahin Dohan
fuente
1

Si tiene un encabezado cors adecuado en su lugar. Su red corporativa puede estar eliminando el encabezado cors. Si el sitio web es accesible desde el exterior, intente acceder desde fuera de su red para verificar si la red está causando el problema, una buena idea independientemente de la causa.

N-ate
fuente
1

En asp.net core, si su controlador api no tiene una anotación llamada [AllowAnonymous], agréguela arriba del nombre de su controlador como

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

No es tan antiguo como otras preguntas, pero simplemente luché con esto en una aplicación Ionic-Laravel, y nada funciona desde aquí (y otras publicaciones), así que instalé https://github.com/barryvdh/laravel-cors complemento en Laravel y comenzó y funciona bastante bien.

gersonmontenegro
fuente
0

La mía fue causada por una relación no válida en los modelos que estaba tratando de consultar. Descubierto al depurar la respuesta, se estrelló en la relación.

J. Kirk.
fuente
0

Para mí no fue un problema angular. Era un campo de tipo DateTime en la base de datos que tiene un valor de (0000-00-00) y mi modelo no puede vincular esa propiedad correctamente, así que cambié a un valor válido como (2019-08-12).

Estoy usando .net core, OData v4 y MySql (conector EF pomelo)

Luis Lopez
fuente
0

Agregue estos códigos en su archivo de conexión

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
fuente
0

Si se trata de un servicio de nodo, pruebe los pasos descritos aquí

Básicamente, es un error de intercambio de recursos de origen cruzado (CORS). Más información sobre estos errores aquí. .

Una vez que actualicé mi servicio de nodo con las siguientes líneas, funcionó:

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();
  });
Puño de la furia
fuente
-2

Mi error fue que el archivo era demasiado grande (el núcleo de dotnet parece tener un límite de @ ~ 25Mb). Ajuste

  • maxAllowedContentLength a 4294967295 (valor máximo de uint) en web.config
  • decorando la acción del controlador con [DisableRequestSizeLimit]
  • services.Configure (opciones => {opciones.MultipartBodyLengthLimit = 4294967295;}); en Startup.cs

resolvió el problema por mí.

Spikolynn
fuente