miércoles, 3 de abril de 2019

Error al usar servicio Northwind con SAPUI5 - Aprendiendo a buscar errores

La semana pasada, dos lectores comentaron que el ejemplo para crear una aplicación usando el servicio oData de Northwind no funcionaba. La verdad es que el error no era nada intuitivo, "HTTP request failed", así que probé a volver a crear la aplicación a ver qué fallaba. Y, efectivamente, ahí estaba el error.

Por todos los draconianos de Krynn, yo juraría que esto antes funcionaba

¿Qué es lo que podía pasar? ¿Por qué había comenzado a fallar? Había que investigar para descubrirlo.

Buscando el error


El primer y evidente paso era probar la dirección del servicio oData, a ver si funcionaba. Consultando en mi propio post, utilicé la URL del documento de servicio directamente para ver si ya no estaba disponible, http://services.odata.org/V2/Northwind/Northwind.svc/. Y sí, la web cargaba... pero había una pequeña diferencia, y es que yo estaba usando http y me redirigía a https. Así que la cosa ya comenzaba a dar pistas.

Además de probar eso, cuando cargué la aplicación accedí a las herramientas para desarrolladores (tecla F12). Esto nos abre una ventana (en cualquier navegador moderno) donde tenemos varias pestañas útiles. El nombre y formato de las mismas depende del navegador, el ejemplo que aquí vamos a ver está hecho con Chrome, pero es fácil seguir los mismos pasos en otros navegadores. 

En la pestaña Console podemos ver los mensajes que nos va emitiendo la web, y ahí nos destacarán los errores en rojo, ya sean errores de acceso, errores de javascript, etc. Ojo, que a veces podemos tener errores que no son importantes, hay que saber qué error buscar.

En este ejemplo, en la consola podemos ver un error, el temido error por política CORS. ¿Qué es esto?


CORS y XSS


Vale, a ver si puedo explicarlo sin meterme en un berenjenal...

El CORS (Cross Origin Resource Sharing) es un mecanismo que nos permite usar (o no) determinados recursos que no están en el dominio de nuestra web, sino en otro distinto. Eso es lo que estamos haciendo en nuestras aplicaciones SAPUI5: La página web (la parte HTML, por así decirlo) nos la proporciona el servidor hanatrial.ondemand.com pero el servicio oData (los datos que vamos a recuperar) está en otro servidor (en este ejemplo, en services.odata.org).

Si los navegadores permitiesen el uso de determinados recursos sin protegernos, podemos sufrir ataques de tipo XSS (cross-site scripting), por ejemplo alguien inyectando código JavaScript en la aplicación para que se haga una llamada a otro dominio diferente del que estamos. Podemos enterarnos más sobre XSS en esta página (en inglés), entre muchas otras.

Chrome nunca nos permite hacer estas llamadas si no se cumplen con las directivas oportunas, es una propiedad que no podemos cambiar (bueno, sí que podemos, pero no es tema baladí). En Internet Explorer podemos permitir que se ignore este mecanismo, pero podemos darnos por enterados de que esto no es seguro. Además, no podemos pensar en construir una web pensando en que valga sólo en ese escenario, un navegador específico y una configuración específica. No suena muy usable, ¿verdad?

Si la infraestructura fuese nuestra (podemos configurar ambos servidores), podríamos intercambiar credenciales en las cabeceras http para que este error no se produzca, pero eso implica configurar tanto en el lado del cliente como en el del servidor. Y eso, en nuestro caso, no es posible :(.

Así que, en resumen, por eso nos está fallando la aplicación: Distinto dominio, no hay credenciales, así que el navegador nos dice naranjas de la Tierra Media.

¿Por qué nos ha funcionado hasta ahora en nuestros ejemplos?


¡Vale, esa me la sé! Porque nosotros nunca hemos llamado directamente a services.odata.org. Nos creábamos un destination en Cloud Platform, y él hace de proxy inverso (dispatcher), ocultando dichas llamadas al navegador. Si vemos en cualquier aplicación a qué url llama el servidor para obtener los datos (en la pestaña Network), no veremos "service.odata.org" sino algo como "https://webidetesting<datos_raros>.dispatcher.hanatrial.com/<mas_datos_raros>".

Cuando el Cloud Platform ve una llamada con ese patrón, internamente hace una llamada a la ubicación del servicio oData. Nuestro navegador ni se entera de que estamos llamando a otro servidor. Eso es lo mismo que hace el famoso SAP Web Dispatcher en on-premise (que no deja de ser un proxy inverso). Lo que pasa es que, hasta ahora, puede que ni nos hubiésemos enterado de toda esta historia.

El problema es que ahora, de repente, parece que estamos llamando directamente a service.odata.org en lugar de utilizar el dispatcher del Cloud Platform. ¿Qué ha podido ocurrir?

Si consultamos la pestaña Network de la herramienta de desarrolladores, veremos las distintas llamadas que hacemos. Tenemos que ponernos a investigar un rato, y descubriremos una llamada $batch que nos da un código de estado 301. Espera, ¿por qué no nos da un 200, que es que todo marcha ok?

Aquí está el culpable

Vale, vale, no sabemos que es eso del 301, pero nos lo podemos oler. Si vemos la cabecera de respuesta de esa llamada, veremos que ¡estamos accediendo a services.odata.org! Vale, ahí está el error por incumplir la política de mismo origen (same-origin policy). Ese 301 significa que hemos accedido al servidor tras haber sido redireccionados. Es decir, que hemos llegado a una URL distinta de la que hemos llamado. Y nos ha ocurrido porque nosotros hemos llamado usando http y el servidor nos ha redirigido a https.

¡Ahí está el error! Posiblemente, en el momento de escribir el artículo esa URL no se redireccionaba y, en algún momento, decidieron pasarlo a HTTPS. ¿Sería desde que Google decidiera marcar todas las web http como inseguras en su Google Chrome?

En cualquiera caso, eso quiere decir que el artículo no está bien.

Arreglando el error


Eso nos lleva a pensar que el destination está mal. Ok, accedemos a él en Cloud Platform para modificarlo (podemos ver cómo modificarlo aquí sin no nos acordamos).

Elegimos nuestro destination y lo probamos pulsando "Check Connection". Y entonces nos da un 301. Así que ahí tenemos al culpable.

Como diría el Gila informático, alguien ha redirigido a alguien...

Lo único que tenemos que hacer es cambiar la URL de http a https. Al hacerlo, nos aparecerán tres campos nuevos (en esta imagen se ven abajo), relacionados con el certificado de confianza.


Simplemente le decimos que use la ubicación por defecto que nos proporciona SAP Cloud Platform.


Y al salvar y chequear la conexión, ¡ya volvemos a tener el 200!

Ya está, todo bien de nuevo

Para que se hagan efectivos los cambios, tenemos que esperar cinco minutos o cerrar el Web IDE y volverlo abrir. Y al volver a probar la aplicación, ya nos volvería a funcionar correctamente.

Al menos me podía currar un poco la aplicación y haber hecho las traducciones...

Y si consultamos la pestaña de Network, veremos que la llamada ya no se redirige a https. Es más, en ningún sitio vemos ahora una llamada al servidor services.odata.org.


Hala, ya está, aplicación como nueva. La que hemos armado por básicamente un ¡Hola, Mundo oData! :D.

2 comentarios: