informatica:programacion:cursos:programacion_avanzada_javascript:ajax
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| informatica:programacion:cursos:programacion_avanzada_javascript:ajax [2024/10/14 11:14] – [JSONP para acceso a otros dominios] tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:ajax [2024/10/30 15:46] (actual) – [Funcionamiento básico de CORS] tempwin | ||
|---|---|---|---|
| Línea 20: | Línea 20: | ||
| La tendencia actual en todos los desarrollos web, sin embargo, es crear **aplicaciones y páginas cada vez más parecidas a aplicaciones de escritorio**, | La tendencia actual en todos los desarrollos web, sin embargo, es crear **aplicaciones y páginas cada vez más parecidas a aplicaciones de escritorio**, | ||
| - | <WRAP center round todo 60%> | + | {{ : |
| - | AJAX | + | |
| - | </ | + | |
| Ya hemos aprendido a lo largo de este curso las posibilidades que ofrecen los navegadores actuales para trabajar en el lado cliente con HTML, CSS y JavaScript. La tendencia imparable en las aplicaciones web es la de **llevar cada vez más procesamiento y lógica al navegador**, | Ya hemos aprendido a lo largo de este curso las posibilidades que ofrecen los navegadores actuales para trabajar en el lado cliente con HTML, CSS y JavaScript. La tendencia imparable en las aplicaciones web es la de **llevar cada vez más procesamiento y lógica al navegador**, | ||
| Línea 390: | Línea 388: | ||
| Dado que HTTP es un protocolo basado en texto, el recurso al que llamemos en el servidor debe devolver siempre texto (o sea, no puede ser una imagen o un archivo binario, que para transferirse se codifican de una forma especial -Base64- para convertirlos en texto). | Dado que HTTP es un protocolo basado en texto, el recurso al que llamemos en el servidor debe devolver siempre texto (o sea, no puede ser una imagen o un archivo binario, que para transferirse se codifican de una forma especial -Base64- para convertirlos en texto). | ||
| - | Este texto devuelto puede tener cualquier formato: **texto plano, XML, código JavaScript o incluso HTML**. En este último caso podemos obtener desde el servidor un contenido HTML completo que se debe escribir en una zona de la página (por ejemplo dentro de un '' | + | Este texto devuelto puede tener cualquier formato: **texto plano, XML, código JavaScript o incluso HTML**. En este último caso podemos obtener desde el servidor un contenido HTML completo que se debe escribir en una zona de la página (por ejemplo dentro de un '' |
| Sin embargo, la mayor parte de las veces lo que tendremos que **procesar es alguna estructura de datos**. | Sin embargo, la mayor parte de las veces lo que tendremos que **procesar es alguna estructura de datos**. | ||
| Línea 481: | Línea 479: | ||
| La medida de seguridad y control más generalizada en los navegadores es la imposibilidad de acceso a recursos de otros dominios. Ya hemos presentado este problema en una lección anterior. | La medida de seguridad y control más generalizada en los navegadores es la imposibilidad de acceso a recursos de otros dominios. Ya hemos presentado este problema en una lección anterior. | ||
| - | En cualquier navegador cada dominio es una zona aislada de las demás. Este aislamiento impide que, por defecto, se puedan transferir cookies entre dominios, que fallen los scripts que tratan de afectar a marcos con páginas que están en dominios diferentes y, por supuesto, tampoco permite hacer peticiones desde código JavaScript a servidores que están en dominios diferentes a la actual. Y aun así existen cantidad de vulnerabilidades (Cross Site Scripting, Cross Site Request Forgery, Cross Zone Scripting, etc...) relacionadas con robo de información y ataques distribuidos que están basadas en explotar código de JavaScript en aplicaciones mal construidas. | + | En cualquier navegador |
| - | | + | <WRAP center round info 60%> |
| + | Al final, cómo esté escrito el código de una aplicación web desde el punto de vista de la seguridad es más importante que todos los cortafuegos y otras medidas "de protocolo" | ||
| + | </ | ||
| - | Una de las implicaciones de este aislamiento entre dominios es que desde nuestro código JavaScript no podremos llamar a servicios Web que estén ubicados en dominios diferentes al nuestro (con XmlHttpRequest). Esto limita la capacidad de agregar información de diversas aplicaciones para explotarla directamente desde el navegador en nuestros desarrollos. Así que por defecto olvídate de llamar a código de Google, Twitter, Flicker, Facebook, YouTube, etc... y mostrar toda esa información agregada en tu página haciéndolo directamente desde JavaScript con los métodos convencionales. | + | |
| + | Una de las implicaciones de este aislamiento entre dominios es que **desde nuestro código JavaScript no podremos llamar a servicios Web que estén ubicados en dominios diferentes al nuestro** (con '' | ||
| Como hemos comentado antes, una solución habitual pasa por construir servicios web propios alojados en nuestro dominio, que actúen como intermediarios de otros servicios y nos devuelvan desde nuestro propio servidor la información que necesitemos, | Como hemos comentado antes, una solución habitual pasa por construir servicios web propios alojados en nuestro dominio, que actúen como intermediarios de otros servicios y nos devuelvan desde nuestro propio servidor la información que necesitemos, | ||
| - | Otra solución alternativa se denomina JSONP (JSON with Padding). Fue propuesta en diciembre de 2005 por Bob Ippolito, creador de la biblioteca JavaScript Mochikit y actualmente trabajador de Facebook. Desde entonces ha sido adoptada por cada vez más aplicaciones Web 2.0 como forma de permitir las llamadas a servicios cross-domain. | + | Otra solución alternativa se denomina |
| - | Se trata de una manera de extender la sintaxis de JSON para que soporte llamadas desde otros dominios. Necesita la colaboración del servidor que expone los servicios para generar el código con una determinada sintaxis, y se aprovecha de que las etiquetas < | + | Se trata de una manera de extender la sintaxis de JSON para que soporte llamadas desde otros dominios. |
| Por ejemplo, una estructura de datos JSON común podría ser ésta: | Por ejemplo, una estructura de datos JSON común podría ser ésta: | ||
| + | <code javascript> | ||
| { Nombre : "José Manuel" | { Nombre : "José Manuel" | ||
| + | </ | ||
| Como hemos visto, la forma habitual de procesar estos datos por parte de un cliente JavaScript es evaluándolos para crear un objeto JavaScript asignado a una variable y luego hacer uso de ellos. | Como hemos visto, la forma habitual de procesar estos datos por parte de un cliente JavaScript es evaluándolos para crear un objeto JavaScript asignado a una variable y luego hacer uso de ellos. | ||
| Línea 501: | Línea 504: | ||
| Sin embargo hay otra manera de recibir en el navegador ese código de script y que no implica usar el objeto XHR. Podemos escribir una etiqueta como esta o generarla dinámicamente usando JavaScript (que es lo más habitual): | Sin embargo hay otra manera de recibir en el navegador ese código de script y que no implica usar el objeto XHR. Podemos escribir una etiqueta como esta o generarla dinámicamente usando JavaScript (que es lo más habitual): | ||
| + | <code html> | ||
| <script type=" | <script type=" | ||
| + | </ | ||
| - | En el atributo src indicamos el URL del servicio que nos va a proporcionar los datos. Estos se recibirán en el lado cliente sin problema a pesar de las restricciones entre dominios. | + | En el atributo |
| - | Sin embargo, | + | Sin embargo, |
| Este problema se solucionaría si pudiésemos procesar o asignar de alguna manera los datos recibidos desde el servidor remoto. Es aquí donde entra en juego la colaboración de éste. | Este problema se solucionaría si pudiésemos procesar o asignar de alguna manera los datos recibidos desde el servidor remoto. Es aquí donde entra en juego la colaboración de éste. | ||
| - | Si definimos en nuestro código JavaScript una función especializada en tratar la información devuelta y conseguimos que el servidor remoto devuelva, no sólo los datos " | + | Si definimos en nuestro código JavaScript una función especializada en tratar la información devuelta y conseguimos que el servidor remoto devuelva, no sólo los datos " |
| - | Esta función puede ser una cuyo nombre esté previamente acordado, o bien una que se indique de manera dinámica y que el servidor utilizará como si se tratara de un método de retrollamada o callback: | + | Esta función puede ser una cuyo nombre esté previamente acordado, o bien una que se indique de manera dinámica y que el servidor utilizará como si se tratara de un método de retrollamada o //callback//: |
| + | <code html> | ||
| <script type=" | <script type=" | ||
| + | </ | ||
| Por ejemplo, si tenemos en nuestro script una función llamada ProcesaDatos que se especializa en recibir objetos JSON y procesarlos, | Por ejemplo, si tenemos en nuestro script una función llamada ProcesaDatos que se especializa en recibir objetos JSON y procesarlos, | ||
| - | En este ejemplo el servidor está de acuerdo en este tipo de procesamiento, | + | En este ejemplo el servidor está de acuerdo en este tipo de procesamiento, |
| + | <code javascript> | ||
| ProcesaDatos( { Nombre : "José Manuel" | ProcesaDatos( { Nombre : "José Manuel" | ||
| + | </ | ||
| - | Lo que tenemos pues es una llamada automática a nuestra función con datos obtenidos desde otro servidor. ¡Justo la llamada entre dominios que estábamos buscando!. Es una forma de retrollamada o callback entre dominios usando JavaScript. | + | Lo que tenemos pues es **una llamada automática a nuestra función con datos obtenidos desde otro servidor**. ¡Justo la llamada entre dominios que estábamos buscando!. Es una forma de retrollamada o //callback// entre dominios usando JavaScript. |
| + | |||
| + | <WRAP center round info 60%> | ||
| + | **API**: Interfaz de Programación de Aplicaciones. Un conjunto de funciones expuestas por un programa para poder ser automatizado desde otros programas. Habilitan la posibilidad de utilizar funcionalidad de unos programas desde otros. | ||
| + | </ | ||
| Esta técnica de JSONP tiene muchas aplicaciones y está soportada también como método de llamadas a recursos remotos por parte de las bibliotecas de JavaScript más populares, como jQuery. Además en la actualidad muchas APIs de servicios on-line soportan ser llamados de esta manera. | Esta técnica de JSONP tiene muchas aplicaciones y está soportada también como método de llamadas a recursos remotos por parte de las bibliotecas de JavaScript más populares, como jQuery. Además en la actualidad muchas APIs de servicios on-line soportan ser llamados de esta manera. | ||
| - | Una biblioteca propia para JSONP | + | |
| + | ==== Una biblioteca propia para JSONP ==== | ||
| Para trabajar con JSONP lo único que hay que hacer es generar dinámicamente un nodo de tipo script en la página y agregarlo a algún lugar del documento (por regla general en la cabecera). Al hacerlo éste se procesa por parte de la página, lo que provoca que se descargue su código fuente y se ejecute. Podemos conseguirlo gracias a la magia del DOM, que nos permite añadir o quitar nodos a voluntad en el documento. | Para trabajar con JSONP lo único que hay que hacer es generar dinámicamente un nodo de tipo script en la página y agregarlo a algún lugar del documento (por regla general en la cabecera). Al hacerlo éste se procesa por parte de la página, lo que provoca que se descargue su código fuente y se ejecute. Podemos conseguirlo gracias a la magia del DOM, que nos permite añadir o quitar nodos a voluntad en el documento. | ||
| - | He escrito una pequeña utilidad que nos facilita el uso de JSONP en cualquier página con solo incluir el archivo .js correspondiente. No tiene dependencias con ninguna otra biblioteca y no interferirá tampoco con otras variables globales que puedas tener. Se llama JSONPHelper.js y lo tienes en los ejemplos descargables de este módulo. | + | He escrito una pequeña utilidad que nos facilita el uso de JSONP en cualquier página con solo incluir el archivo |
| El código es el siguiente: | El código es el siguiente: | ||
| + | <code javascript> | ||
| var sendJsonpRequest = (function () { | var sendJsonpRequest = (function () { | ||
| var queryScript; | var queryScript; | ||
| Línea 557: | Línea 572: | ||
| }; | }; | ||
| })(); | })(); | ||
| + | </ | ||
| El código puede parecer un poco lioso, pero vete acostumbrándote pues la mayor parte del código JavaScript actual se escribe de este modo. | El código puede parecer un poco lioso, pero vete acostumbrándote pues la mayor parte del código JavaScript actual se escribe de este modo. | ||
| - | Lo que se hace es guardar en una variable de nombre sendJsonpRequest el resultado de ejecutar una función anónima (fíjate en los paréntesis de la última línea, utilizados para forzar la ejecución de esta función anónima). Ésta lo único que hace es devolver otra función asociándola a la variable. De este modo, la variable pasa a convertirse en una función que podemos llamar como cualquier otra. La ventaja de hacerlo así, es que gracias al poder de las clausuras, es posible manejar variables internas privadas sin necesidad de convertirlas en variables globales externas a la función (en este caso la que se llama queryScript, | + | Lo que se hace es guardar en una variable de nombre |
| Bien, entonces la verdadera funcionalidad está en esa función interna destacada en negrita que toma cuatro parámetros: | Bien, entonces la verdadera funcionalidad está en esa función interna destacada en negrita que toma cuatro parámetros: | ||
| - | | + | * '' |
| - | callback: el nombre de la función callback con la que envolverá la llamada el servicio al que llamamos. Debe ser una cadena de texto. | + | * '' |
| - | error: parámetro opcional que, en caso de que lo pasemos, contendrá una referencia a la función que se llamará en caso de que se produzca un error (generalmente el error será el de página no encontrada si pedimos una información no disponible). Si no se facilita simplemente no se notifica ningún error. | + | * '' |
| - | nomparam: parámetro opcional que nos sirve para indicar cómo se llama el parámetro que debemos pasar al URL en el que indicamos el nombre de la función de callback con la que se envolverá la información devuelta. Sería la f del URL de ejemplo anterior. Generalmente se llama callback, y este será el nombre usado por defecto en nuestro código, pero en algunos servicios puede cambiar. | + | |
| + | |||
| + | El código es muy sencillo. Lo que hace primeramente es comprobar si se pasa o no el cuarto parámetro opcional. Si no es así le pone el nombre por defecto '' | ||
| - | El código es muy sencillo. Lo que hace primeramente es comprobar | + | A continuación, |
| - | A continuación, | + | Ahora ya viene el código que lanza la petición JSONP. Se localiza la cabecera de la página. Si ya le habíamos añadido algún script debido a una llamada anterior por JSONP lo eliminamos pues ya no nos hace falta (así ahorramos memoria). Se crea un elemento de tipo '' |
| - | + | ||
| - | Ahora ya viene el código que lanza la petición JSONP. Se localiza la cabecera de la página. Si ya le habíamos añadido algún script debido a una llamada anterior por JSONP lo eliminamos pues ya no nos hace falta (así ahorramos memoria). Se crea un elemento de tipo < | + | |
| Si hay algún manejador de errores especificado se asigna al evento onerror del script, que salta si se produce cualquier error, por ejemplo que no cargue. Lo asignamos con el modelo del BOM porque estamos seguros de que seremos los únicos que lo van a usar, ya que creamos dinámicamente ese nodo y sólo está accesible desde nuestra función gracias a la clausura. | Si hay algún manejador de errores especificado se asigna al evento onerror del script, que salta si se produce cualquier error, por ejemplo que no cargue. Lo asignamos con el modelo del BOM porque estamos seguros de que seremos los únicos que lo van a usar, ya que creamos dinámicamente ese nodo y sólo está accesible desde nuestra función gracias a la clausura. | ||
| Línea 579: | Línea 595: | ||
| Finalmente añadimos el nodo de script a la cabecera de la página. Al hacerlo el navegador lo procesa para lo cual descarga el código indicado en src y lo ejecuta. | Finalmente añadimos el nodo de script a la cabecera de la página. Al hacerlo el navegador lo procesa para lo cual descarga el código indicado en src y lo ejecuta. | ||
| - | Lo que hemos conseguido es una ejecución dinámica de un script que está ubicado en otro servidor. | + | Lo que hemos conseguido es una **ejecución dinámica de un script que está ubicado en otro servido**r. |
| Con esta función a mano es muy fácil llamar a cualquier API basada en JSONP, como veremos a continuación con un ejemplo. | Con esta función a mano es muy fácil llamar a cualquier API basada en JSONP, como veremos a continuación con un ejemplo. | ||
| - | ===== ===== | + | ===== DEMO: Una base de datos de películas con JSONP ===== |
| - | ===== ===== | + | Ejemplo de uso de JSONP para crear un buscador de películas en una fuente externa ([[https:// |
| + | |||
| + | <WRAP center round important 60%> | ||
| + | IMPORTANTE: todo lo explicado en el vídeo a continuación es correcto y sigue funcionando perfectamente. La única salvedad es que, desde que se grabó, la API de OMDB ha decidido utilizar una clave de API para evitar abusos. Esta clave es gratuita (para 1.000 llamadas al día) y es muy fácil de obtener usando el enlace correspondiente del menú en la web. No obstante en la descarga de ejemplo he incluido una API mía para que puedas probarlo sin problemas. Todo lo demás es idéntico a lo explicado en el vídeo. | ||
| + | </ | ||
| + | |||
| + | El HTML: | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | <html lang=" | ||
| + | < | ||
| + | <meta charset=" | ||
| + | < | ||
| + | |||
| + | <link type=" | ||
| + | |||
| + | <script type=" | ||
| + | <script type=" | ||
| + | <script type=" | ||
| + | </ | ||
| + | < | ||
| + | <div id=" | ||
| + | <div id=" | ||
| + | <input type=" | ||
| + | <input type=" | ||
| + | <div id=" | ||
| + | <div id=" | ||
| + | & | ||
| + | </ | ||
| + | <div id=" | ||
| + | <div id=" | ||
| + | <h1 id=" | ||
| + | <p id=" | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | <div id=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | Scripts usados: | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | El contenido de '' | ||
| + | |||
| + | <code javascript> | ||
| + | var IMDB_API_URL = " | ||
| + | var IMDB_API_KEY = " | ||
| + | |||
| + | function hacerBusqueda() { | ||
| + | var titPelicula = document.getElementById(" | ||
| + | if (titPelicula.trim() == "" | ||
| + | alert(" | ||
| + | document.getElementById(" | ||
| + | } | ||
| + | |||
| + | sendJsonpRequest(IMDB_API_URL + "? | ||
| + | } | ||
| + | |||
| + | function titPelicula_OnEnter(event) { | ||
| + | event = EventHandlerHelper.fixEvent(event); | ||
| + | if (event.which == 13) | ||
| + | hacerBusqueda(); | ||
| + | } | ||
| + | |||
| + | //Muestra resultados de búsqueda (función callback de JSONP) | ||
| + | function mostrarResultadosBusquedaCallback(resultados) { | ||
| + | var resHTML = ""; | ||
| + | |||
| + | if (!resultados.Search || resultados.Search.length == 0){ | ||
| + | resHTML = "< | ||
| + | } | ||
| + | else { | ||
| + | for(var i = 0; i< | ||
| + | { | ||
| + | var res = resultados.Search[i]; | ||
| + | resHTML += "<p data-imdbid='" | ||
| + | } | ||
| + | } | ||
| + | document.getElementById(" | ||
| + | ocultarDetalles(); | ||
| + | } | ||
| + | |||
| + | //Si no se encuentra la API | ||
| + | function error404() | ||
| + | { | ||
| + | document.getElementById(" | ||
| + | ocultarDetalles(); | ||
| + | } | ||
| + | |||
| + | //Muestra info de la película a partir de un identificador | ||
| + | //Se le pasa el elemento sobre el que se ha pulsado | ||
| + | function mostrarInfoPeli(elto) { | ||
| + | var idPelicula = elto.attributes[" | ||
| + | //Desmarco las que hubiese seleccionadas | ||
| + | var seleccionados = document.getElementsByClassName(" | ||
| + | for(var i = 0; i< seleccionados.length; | ||
| + | seleccionados[i].className = ""; | ||
| + | } | ||
| + | //La marco como seleccionada | ||
| + | elto.className = " | ||
| + | //Pido la info sobre la película | ||
| + | sendJsonpRequest(IMDB_API_URL + "? | ||
| + | } | ||
| + | |||
| + | //Muetra información de una película (función callback de JSONP) | ||
| + | function mostrarInfoPeliculaCallback(peli){ | ||
| + | if (peli != null && !peli.Error) | ||
| + | { | ||
| + | //Asignamos a mano la imagen | ||
| + | if (peli.Poster == " | ||
| + | document.getElementById(" | ||
| + | else { | ||
| + | document.getElementById(" | ||
| + | document.getElementById(" | ||
| + | } | ||
| + | //Ahora asignamos el resto de los campos | ||
| + | enlazarCamposConDOM(peli); | ||
| + | mostrarDetalles(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | //Se encarga de localizar campos en la página con el mismo nombre que campos de un objeto que se le pasa, e introduce su valor como contenido en cada uno de ellos | ||
| + | function enlazarCamposConDOM(obj) { | ||
| + | //Si no se pasa un elemento concreto del DOM a partir del cual buscar, se usa document y se busca en toda la página | ||
| + | //Se recorren las propiedades del objeto | ||
| + | for (prop in obj) { | ||
| + | // | ||
| + | var e = document.getElementById(prop); | ||
| + | if (e != null) { | ||
| + | e.textContent = obj[prop]; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | //Mostrar detalles película | ||
| + | function mostrarDetalles(){ | ||
| + | document.getElementById(" | ||
| + | } | ||
| + | |||
| + | //Ocultar detalles película | ||
| + | function ocultarDetalles(){ | ||
| + | document.getElementById(" | ||
| + | } | ||
| + | |||
| + | function initialize() { | ||
| + | EventHandlerHelper.addEventListener(document.getElementById(" | ||
| + | EventHandlerHelper.addEventListener(document.getElementById(" | ||
| + | } | ||
| + | |||
| + | window.onload = initialize; | ||
| + | </ | ||
| + | |||
| + | <WRAP center round tip 60%> | ||
| + | Visor online para JSON: https:// | ||
| + | </ | ||
| ===== Control de acceso entre dominios: CORS ===== | ===== Control de acceso entre dominios: CORS ===== | ||
| + | |||
| + | La funcionalidad de JSONP que acabamos de estudiar es muy interesante para crear //mashups// y manejar información de otros dominios de manera directa desde el navegador. Sin embargo, hay que tener cuidado cuando se usa con información privada importante ya que **no está exenta de problemas de seguridad**. Por algo los que diseñan los navegadores se empeñan en no permitir el acceso entre dominios. | ||
| + | |||
| + | <WRAP center round info 60%> | ||
| + | **Mashups**: | ||
| + | </ | ||
| + | |||
| + | No voy a entrar en detalles aquí sobre técnicas de //phising// que usan JavaScript para obtener ilícitamente información de otros dominios mediante JSONP, pero baste decir que Twitter o el mismísimo GMail fueron craqueados hace años usando técnicas de [[https:// | ||
| + | |||
| + | El protegerse de esas técnicas de //hacking// depende del servicio que implementa la API JSONP. Sólo deberíamos usarlo en nuestras páginas si confiamos en estos sitios. Utilizar APIs de servicios poco recomendables podría resultar en problemas de seguridad para nuestros usuarios. | ||
| + | |||
| + | Además JSONP tiene bastantes limitaciones: | ||
| + | |||
| + | * Sólo sirve para peticiones GET | ||
| + | * Los datos deben devolverse en formato JSON, o sea, JavaScript. Si necesitamos otros formatos no lo tenemos fácil. | ||
| + | * La información que se puede enviar al servidor es muy limitada (únicamente datos planos como parámetros de la URL). | ||
| + | * El servidor debe colaborar explícitamente con el método para devolver el código envuelto en una llamada a un método JavaScript, algo que no siempre está en nuestra mano. | ||
| + | * No existe un método estándar para controlar el acceso a este tipo de recursos remotos por parte del servidor que los provee, es decir, decidir quién y cuándo puede acceder al recurso. | ||
| + | |||
| + | Así que, realmente, **la mejor manera de crear aplicaciones AJAX sigue siendo usar el objeto '' | ||
| + | |||
| + | Conscientes de ello el W3C trabajó en un **estándar que modifica el modo de funcionamiento tradicional** del objeto '' | ||
| + | |||
| + | Los principales navegadores lo han implementado hace bastante tiempo (Internet Explorer desde la versión 8, Opera desde la 12). Si te interesa puedes leer el estándar completo aquí: [[http:// | ||
| + | |||
| + | <WRAP center round important 60%> | ||
| + | Nota: Muchos programadores cuando oyen hablar de CORS piensan en un protocolo de seguridad para proteger el acceso a los recursos, de manera similar a tener una clave o usar un mecanismo de cifrado o algo similar. Se trata de **un error de concepto**. CORS no pretende proteger el acceso a las aplicaciones de servidor. No es un método de seguridad para servicios en Internet. Lo que busca es **proteger a los usuarios frente a ataques de phishing y XSRF** para que no sean víctimas de un pirata de forma inadvertida, | ||
| + | </ | ||
| + | |||
| + | ==== Funcionamiento básico de CORS ==== | ||
| + | |||
| + | CORS define un protocolo entre los servidores Web y los navegadores para que colaboren a la hora de delimitar políticas de seguridad de acceso entre dominios. | ||
| + | |||
| + | Así, en su forma más básica, CORS define que cuando se haga una llamada con XHR a un dominio diferente del actual, **dicha llamada debe incluir automáticamente información sobre quién realiza la petición**. Así ésta incluirá automáticamente una cabecera llamada " | ||
| + | |||
| + | <WRAP center round info 60%> | ||
| + | Nota: Esta cabecera difiere de la cabecera " | ||
| + | </ | ||
| + | |||
| + | Con esta cabecera el servidor decide si permite o no el acceso al recurso, devolviendo en su respuesta una cabecera de tipo " | ||
| + | |||
| + | Por ejemplo, puede devolver: | ||
| + | |||
| + | < | ||
| + | Access-Control-Allow-Origin: | ||
| + | </ | ||
| + | |||
| + | Al recibir esta cabecera el navegador sabe si debe permitir o no que se realice la llamada. De esta forma se protege a los usuarios, ya que si alguien intenta un ataque XSRF contra un servicio como GMail, al realizar la petición desde otro dominio distinto al esperado ('' | ||
| + | |||
| + | Por defecto, si el servidor no incluye esta cabecera el navegador bloquea la llamada, con lo que el comportamiento es exactamente el mismo que el tradicional. | ||
| + | |||
| + | En muchos casos, si el servicio quiere que pueda consumirse desde cualquier dominio, puede devolver esto: | ||
| + | |||
| + | < | ||
| + | Access-Control-Allow-Origin: | ||
| + | </ | ||
| + | |||
| + | Esto significa que admite peticiones desde cualquier dominio externo. Ideal para servicios que no juegan con datos privados y quieren abrirse a cuantos más usuarios externos mejor. | ||
| + | |||
| + | La especificación CORS define todavía más cabeceras para cuestiones algo más especializadas, | ||
| + | |||
| + | Lo mejor de CORS es que nosotros, como programadores JavaScript no tenemos que hacer nada especial para soportar estas llamadas entre dominios. Nos limitamos a utilizar el objeto XHR como siempre, de la manera explicada en este tema. La única diferencia es que tenemos que incluir el URL completo, con el nombre de otro dominio. | ||
| + | |||
| + | A la hora de utilizar un servicio externo desde uno de tus desarrollos JavaScript, intenta averiguar si el servicio implementa cabeceras CORS de tipo " | ||
| + | ===== Recursos ===== | ||
| + | |||
| + | * [[https:// | ||
informatica/programacion/cursos/programacion_avanzada_javascript/ajax.1728897286.txt.gz · Última modificación: por tempwin
