Node Js
Node Js
JS
Un ejemplo de solicitud de origen cruzado: el código JavaScript frontend de una aplicación web que
es localizada en http://domain-a.com utiliza XMLHttpRequest para cargar el
recurso http://api.domain-b.com/data.json.
Por razones de seguridad, los exploradores restringen las solicitudes HTTP de origen cruzado
iniciadas dentro de un script. Por ejemplo, XMLHttpRequest y la API Fetch siguen la política de
mismo-origen. Ésto significa que una aplicación que utilice esas APIs XMLHttpRequest sólo puede
hacer solicitudes HTTP a su propio dominio, a menos que se utilicen cabeceras CORS.
• Invocaciones de las APIs XMLHttpRequest o Fetch en una manera de sitio cruzado, como
se discutió arriba.
• Fuentes Web (para usos de fuente en dominios cruzados @font-face dentro de CSS), para
que los servidores puedan mostrar fuentes TrueType que sólo puedan ser cargadas por sitios
cruzados y usadas por sitios web que lo tengan permitido.
• Texturas WebGL.
• Imágenes dibujadas en patrones usando drawImage.
• Hojas de estilo (para acceso CSSOM).
• Scripts (para excepciones inmutadas).
Este artículo es una discusión general sobre Intercambio de Recursos de Origin Cruzado e incluye
una discusión sobre las cabeceras HTTP.
Resumen
El estándar de Intercambio de Recursos de Origen Cruzado trabaja añadiendo nuevas cabeceras
HTTP que permiten a los servidores describir el conjunto de orígenes que tienen permiso para leer
la información usando un explorador web. Adicionalmente, para métodos de solicitud HTTP que
causan efectos secundarios en datos del usuario (y en particular, para otros métodos HTTP distintos
a GET, o para la utilización de POST con algunos tipos MIME), la especificación sugiere que los
exploradores "verifiquen" la solicitud, solicitando métodos soportados desde el servidor con un
método de solicitud HTTP OPTIONS, y luego, con la "aprobación" del servidor, enviar la verdadera
solicitud con el método de solicitud HTTP verdadero. Los servidores pueden también notificar a los
clientes cuando sus "credenciales" (incluyendo Cookies y datos de autenticación HTTP) deben ser
enviados con solicitudes.
Las secciones siguientes discuten escenarios, así como el análisis de las cabeceras HTTP usados.
Ejemplos de escenarios de control de accesos
Aquí, presentamos tres escenarios que ilustran cómo funciona el Intercambio de Recursos de Origen
Cruzado. Todos estos ejemplos utilizan el objeto XMLHttpRequest, que puede ser utilizado para
hacer invocaciones de sitios cruzados en cualquier explorador soportado.
Los fragmentos de JavaScript incluidos en estas secciones (y las instancias ejecutadas del código
servidor que correctamente maneja las solicitudes de sitios cruzados) pueden ser encontrados "en
acción" aquí, y pueden ser trabajados en exploradores que soportan XMLHttpRequest de sitios
cruzados. Una discusión de Intercambio de Recursos de Origen Cruzado desde una perspectiva de
servidor (incluyendo fragmentos de código PHP) puede ser encontrada aquí.
Solicitudes simples
Una solicitud de sitio cruzado es aquella que cumple las siguientes condiciones:
Por ejemplo, suponga que el contenido web en el dominio http://foo.example desea invocar
contenido en el dominio http://bar.other. Código de este tipo puede ser utilizado dentro de
JavaScript desplegado en foo.example:
function callOtherDomain() {
if(invocation) {
invocation.onreadystatechange = handler;
invocation.send();
Dejándonos ver lo que el explorador enviará al servidor en este caso, y veamos como responde el
servidor:
Host: bar.other
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin:
Copy tohttp://foo.example
Clipboard
HTTP/1.1 200 OK
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
[XML Data]
Las líneas 1 - 10 son las cabeceras enviadas por Firefox 3.5. Observe que la cabecera de solicitud
HTTP principal aquí es la cabecera Origin: en la línea 10 de arriba, lo que muestra que la
invocación proviene del contenido en el dominio http://foo.example.
Access-Control-Allow-Origin: http://foo.example
Note que ahora, ningún otro dominio aparte de http://foo.example (identificado por la
cabecera ORIGIN: en la solicitud, como en la línea 10 arriba) puede acceder al recurso en una
forma de sitio cruzado. La cabecera Access-Control-Allow-Origin debe contener el valor que fue
enviado en la solicitud del encabezado Origin.
Solicitudes Verificadas
A diferencia de las solicitudes simples (discutidas arriba), las solicitudes "verificadas" envían
primero una solicitud HTTP por el método OPTIONS al recurso en el otro dominio, para determinar
si es seguro enviar la verdadera solicitud. Las solicitudes de sitios cruzados son verificadas así ya
que pueden tener implicaciones en la información de usuario. En particular, una solicitud es
verificada sí:
• Usa métodos distintos a GET, HEAD o POST. También, si POST es utilizado para enviar
solicitudes de información con Content-Type distinto a application/x-www-form-
urlencoded, multipart/form-data, o text/plain, ej. si la solicitud POST envía una carga XML al
servidor utilizando application/xml or text/xml, entonces la solicitud es verificada.
• Se establecen encabezados personalizados (ej. la solicitud usa un encabezado como X-
PINGOTHER)
Nota: Empezando en Gecko 2.0, las codificaciones de datos text/plain, application/x-www-form-
urlencoded, y multipart/form-data pueden ser enviadas en sitios cruzados sin verificación.
Anteriormente, solo text/plain podía ser enviado sin verificación.
Un ejemplo de este tipo de invocación puede ser:
function callOtherDomain(){
if(invocation)
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type',
Copy to Clipboard 'application/xml');
invocation.onreadystatechange = handler;
invocation.send(body);
......
En el ejemplo de arriba, la línea 3 crea un cuerpo XML para enviar con la solicitud POST en la
línea 8. También, en la línea 9, se establece una cabecera HTTP de solicitud "personalizado" (no
estándar X-PINGOTHER: pingpong). Dichas cabeceras no son parte del protocolo HTTP/1.1, pero
son útiles generalmente en aplicaciones web. Dado que la solicitud (POST) usa un Content-
Type application/xml, y dado que se establece una cabecera personalizada, la solicitud es verificada.
Host: bar.other
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000
Content-Encoding: gzip
Content-Length: 0
Connection: Keep-Alive
Content-Type: text/plain
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre)
Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache
<?xml version="1.0"?><person><name>Arun</name></person>
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://foo.example
Content-Encoding: gzip
Content-Length: 235
Connection: Keep-Alive
Content-Type: text/plain
Las líneas 1 - 12 arriba representan la solicitud verificada con los métodos OPTIONS. Firefox 3.1
determina lo que se necesita para enviar esto basándose en los parámetros de la solicitud que los
fragmentos de JavaScript que se usaron arriba, para que el servidor pueda responder si es aceptable
enviar la solicitud con los parámetros de la solicitud real. OPTIONS es un método HTTP/1.1 que se
utiliza para determinar información adicional de los servidores, y es un método idempotente, esto
significa que no puede ser utilizado para cambiar el recurso. Observe que, junto con la solicitud
OPTIONS, se envían otras dos cabeceras de solicitud (líneas 11 y 12 respectivamente):
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER
Las líneas 15 - 27 de arriba corresponden con la respuesta que devuelve el servidor indicando que el
método de la petición (POST) y la cabecera X-PINGOTHER son aceptadas. En particular, echemos
un vistazo a las líneas 18-21:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000
El servidor responde con Access-Control-Allow-Methods y dice que POST, GET, y OPTIONS son
métodos viables para consultar el recurso en cuestión. Observe que esta cabecera es similar
al HTTP/1.1 Allow: encabezado de respuesta, pero usado estrictamente dentro del contexto del
control de acceso. El servidor también envía Access-Control-Allow-Headers con un valor de X-
PINGOTHER, confirmando que es una cabecera permitida para ser usado en la solicitud
real. Como Access-Control-Allow-Methods, Access-Control-Allow-Headers es una lista separada
por comas de cabeceras aceptables. Finalmente, Access-Control-Max-Age da el valor en segundos
de cuánto tarda la respuesta de la solicitud verificada en ser capturada sin enviar otra solicitud
verificada. En este caso, 1728000 segundos son 20 días.
En este ejemplo, el contenido cargado originalmente desde http://foo.example hace una solicitud
GET simple a un recurso en http://bar.other que establece Cookies. El contenido en foo.example
puede contener un JavaScript como este:
function callOtherDomain(){
if(invocation) {
invocation.onreadystatechange = handler;
invocation.send();
La línea 7 muestra la bandera en XMLHttpRequest que tiene que ser establecida para poder hacer la
invocación con Cookies, es decir, el valor booleano withCredentials. Por defecto, la invocación es
hecha sin Cookies. Dado que esta es una simple solicitud GET, no es verificada, pero el
explorador rechazará cualquier respuesta que no tiene el encabezado Access-Control-Allow-
Credentials: true,y no hará disponible la respuesta para invocar contenido web.
Host: bar.other
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2
HTTP/1.1 200 OK
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Content-Encoding: gzip
Content-Length: 106
Connection: Keep-Alive
Content-Type: text/plain
[text/plain payload]
Copy to Clipboard
Pese a que la línea 11 contiene la Cookie destinada para el contenido en http://bar.other, si bar.other
no responde con Access-Control-Allow-Credentials: true (línea 19) la respuesta será ignorada y no
puesta a disposición para el contenido web. Nota Importante: cuando se responde a una solicitud
con credeciales, el servidor debe especificar un dominio, y no puede usar comodines. El ejemplo de
arriba fallará si la cabecera fuera un comodín como: Access-Control-Allow-Origin: *. Dado
que Access-Control-Allow-Origin menciona explícitamente http://foo.example, el contenido de
credenciales competente es devuelto al contenido web invocador. Observe que, en la línea 22, se
establece una cookie adicional.
Todos estos ejemplos pueden verse funcionando aquí. La siguiente sección se refiere a las
verdaderas cabeceras HTTP.
Access-Control-Allow-Origin
Un recurso devuelto puede tener una cabecera Access-Control-Allow-Origin, con la siguiente
sintaxis:
Access-Control-Allow-Origin: <origin> | *
El parámetro origin específica una URI que puede tener acceso al recurso. El explorador debe
asegurar esto. Para solicitudes sin credenciales, el servidor debe especificar "*" como un comodín
permitiendo, de este modo, el acceso al recurso a cualquier origen.
Por ejemplo, para permitir a http://mozilla.com acceder al recurso, usted puede especificar:
Access-Control-Allow-Origin: http://mozilla.com
Si el servidor especifica un host de origen en vez de "*", entonces se debe incluir Origin en el
encabezado de respuesta Vary para indicar a los clientes que las respuestas del servidor difieren
basándose en el valor del encabezado de respuesta Origin.
Access-Control-Expose-Headers
Access-Control-Max-Age
Esta cabecera indica durante cuánto tiempo los resultados de la solicitud verificada pueden ser
capturados. Para un ejemplo de solicitudes verificadas, vea los ejemplos de arriba.
Access-Control-Max-Age: <delta-seconds>
El parámetro delta-seconds indica el número de segundos en que los resultados pueden ser
capturados.
Access-Control-Allow-Credentials
Indica si la respuesta puede ser expuesta cuando la bandera credentials es verdadera. Cuando se usa
como parte de una respuesta para una solicitud verficada, este indica si la solicitud verdadera puede
realizarse usando credenciales. Note que las solicitudes GET simples no son verificadas, y por lo
que si una solicitud es hecha para un recurso con credenciales, si la cabecera no es devuelta con el
recurso, la respuesta es ignorada por el explorador y no devuelta al contenido web.
Access-Control-Allow-Methods
Específica el método o los métodos permitidos cuando se asigna un recurso. Es usado en respuesta a
la solicitud verificada. Las condiciones sobre cuándo una solicitud es verificada se discuten arriba.
Un ejemplo de una solicitud verificada se muestra arriba, incluyendo un ejemplo donde se envía
este encabezado al explorador.
Access-Control-Allow-Headers
Usado en respuesta a una solicitud verificada para indicar qué encabezado HTTP puede ser usado
cuando se realiza la solicitud real.
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
Origin
Indica el origen de las solicitudes de acceso a sitios cruzados o solicitudes verificadas.
Origin: <origin>
El origen es una URI indicando al servidor dónde se ha iniciado la solicitud. Este no incluye
ninguna información de recorrido, sólo el nombre del servidor.
Nota: El origin puede ser un string vacío; esto es útil, por ejemplo, si el recurso es un data URL.
Observe que en cualquier solicitud de acceso de control, la cabecera ORIGIN siempre se envía.
Access-Control-Request-Method
Se usa cuando se emite una solicitud verificada, para indicarle al servidor qué método HTTP será
usado cuando se haga la solicitud real.
Access-Control-Request-Method: <method>
Access-Control-Request-Headers
Usada cuando se emite una solicitud verificada para indicarle al servidor qué cabecera HTTP será
usada cuando se haga la solicitud real.
Para añadir más páginas a nuestro sitio, necesitamos más rutas. Podemos hacerlo usando Express
Router, que ya viene integrado en Express. Esta entrada será un tanto bestia ya que el manejo de las
rutas será una parte importante de todas las aplicaciones que hagamos de ahora en adelante.
Esta es la manera de crear las rutas básicas para sitios web, y también la forma en la que finalmente
construiremos nuestras APIs RESTful que utilizará una app frontend en Angular. Así que, sin más
dilación procedemos a enrutar (que palabra más fea señores, usaremos routing a partir de ahora).
EXPRESS ROUTER
¿Qué es exactamente Express Router? Puedes considerarlo como una mini aplicación de express sin
tantas funcionalidades, solo routing. No incorpora vistas o configuraciones, pero nos proporciona
una routing API con funciones como .use(), .get(), .param(), y route(). Echaremos un vistazo al
significado de todo esto.
Hay varias formas de usar routing. Ya usamos uno de sus métodos cuando creamos la página de
inicio en la anterior entrada usando ‘app.get(‘/’, …). Veremos otros métodos para hacer más
secciones de nuestro sitio y comentaremos el por qué y cuando usarlos.
Como hemos hecho hasta ahora, tendremos nuestras rutas en el archivo server.js. No necesitaremos
hacer cambio alguno en nuestro package.json puesto que ya viene todo instalado con Express.
Está es la forma más simple de definir rutas, pero a medida que nuestra aplicación crezca,
necesitaremos más organización para nuestras rutas. Tan solo imagínate una app que tenga una parte
de administrador y otra parte para el usuario, con muchas rutas cada una. Express router nos ayuda
a regular todo esto.
Para las rutas siguientes, no enviaremos vistas al navegador, solo mensajes. Así será más sencillo ya
que quiero centrarme en los aspectos del routing.
EXPRESS.ROUTER()
express.Router() actúa como una mini aplicación. Puedes crear una instancia (como hicimos con
Express) y luego definir rutas con ella. Vamos a ver un ejemplo.
Debajo nuestro app.get() route dentro del server.js, añade lo siguiente. Vamos a 1. llamar una
instancia del router 2. aplicarle rutas a esa instancia 3. y luego añadir estas rutas a nuestra app
principal.
//instanciamos router
var adminRouter = express.Router();
Observa como podemos establecer una raíz/root por defecto usando estas rutas que acabamos de
definir. Si hubiéramos cambiado la línea 22 por app.use(‘/app’, router), entonces nuestras rutas
serían http://localhost:1337/app/ y http://localhost:1337/app/users.
Esto es muy potente porque podemos creas varias express.Router() y luego aplicarlas a nuestra app.
Podríamos tener un Router para las rutas básicas, rutas de autentificación, etc.
Usar Router nos permite hacer nuestras aplicaciones más modulares y flexibles que nunca mediante
la creación de instancias de Router y aplicándolas como corresponde. Ahora vamos a ver como
usar middleware para manejar peticiones.
El middleware registra un mensaje en nuestra consola cada vez que se realiza una petición /
solicitud. Haremos una demostración de como crear middleware usando Express Router.
Simplemente añadiremos el middleware al adminRouter que creamos en el último ejemplo.
Asegúrate de ponerlo después de declarar tu adminRouter y antes de definir las rutas del admin,
usuarios y posts.
Te habrás fijado en el argumento ‘next’. Es el único modo que tiene Express de saber que la función
se ha completado y puede proceder con la siguiente parte del middleware o continuar con el
enrutamiento (routing).
Es muy importante el orden en que coloques tus middleware y las rutas. Todo ocurre en el orden en
el que están. Significa que si colocas tus middleware después de una ruta, la ruta procedería antes
que el middleware y la petición finalizará ahí mismo. Tu middleware no se ejecutaría en este caso.
Ten en mente que puedes usar el route middleware para muchas cosas. Por ejemplo, puedes usarlo
para comprobar si un usuario se ha logueado durante la sesión antes de dejarlo continuar.
ESTRUCTURANDO RUTAS
Al usar Router(), somos capaces de dividir en partes de nuestro sitio. Significa que puedes crear un
basicRouter para rutas de navegación básica del sitio. También podrías crear un adminRouter para
las rutas como administrador que estarían protegidas por algún tipo de autentificación.
Enrutar nuestra aplicación es un método que nos permite dividir las piezas que la componen. Nos
proporciona la flexibilidad que necesitamos para aplicaciones complejas o APIs. También podemos
mantener nuestra aplicación limpia y organizada ya que podemos trasladar cada router definido a su
propio archivo individual y luego simplemente coger este archivo cuando lo llamamos con
app.use(), de esta manera:
app.use('/', basicRoutes);
app.use('/admin', adminRoutes);
app.use('/api', apiRoutes);
RUTAS CON PARÁMETROS (/HELLO/:NAME)
Vamos a ver como añadir parámetros a las rutas, digamos que queremos tener una ruta llamada
/admin/users/:name donde pasamos el nombre de una persona a la URL, y la aplicación lanza un
---------------------------------------------------------------------------------------------------
//ruta con parámetros (http://localhost:1337/admin/users/:name)
adminRouter.get('/users/:name', function(req, res){
res.send('hola ' + req.params.name + '!');
});
Pongamos como ejemplo que queremos validar el nombre de alguna forma. Quizás queremos
asegurarnos de que no es una palabra ofensiva o políticamente incorrecta. Haríamos esta validación
dentro del middleware. Usaremos un middleware especial para esto.
Usaremos Express .param() middleware. Esto crea un middleware que se ejecutará para cierto
parámetro de la ruta. En nuestro caso, estamos usando :name en nuestra ruta de saludo. Una vez
más, asegúrate de que el middleware está colocado antes que la ruta:
Middleware para parámetros se puede usar para validar datos que se envían a tu aplicación. Si te da
por hacer una API RESTful, puedes validar también un token y asegurarte de que el usuario es
capaz de acceder a su información. Todo lo que hemos trabajado en Node hasta ahora dará lugar a la
API RESTful que comentamos en la primera entrada cuando hablamos del modelo cliente-servidor.
Ahora pasamos a ver la última característica de Express router, cómo usar app.route() para definir
varias rutas de una sola vez.
Usar app.route() nos permite definir varias acciones en una sola ruta de login. Necesitaremos un
GET route para mostrar el formulario de login o acceso y un POST route para procesar el
formulario.
app.route('/login')
//mostramos el formulario (GET http://localhost:1337/login)
.get(function(req, res){
res.send('este es el formulario de login');
})
Listo, ya hemos definido dos acciones diferentes en nuestra ruta /login. Limpio y sencillo. Esta vez
hemos aplicado directamente la ruta a nuestro objeto app dentro del archivo server.js, pero también
podemos definirlas en el objeto adminRouter que teníamos antes.
Este es un buen método para crear rutas, ya que es limpio y facilita ver qué rutas hay y dónde se
aplican. Pronto estaremos haciendo una API RESTful y una de las cosas que debemos hacer es usar
los diferentes verbos de una petición HTTP para las acciones o funciones de nuestra aplicación.
GET /login dará lugar al formulario de acceso (login) mientras que POST /login procesará los datos
de login.
RESUMEN
Express Router nos da mucha flexibilidad a la hora de definir rutas. En resumen, podemos:
• El objeto Promise devuelto desde fetch() no será rechazado con un estado de error
HTTP incluso si la respuesta es un error HTTP 404 o 500. En cambio, este se resolverá
normalmente (con un estado ok configurado a false), y este solo sera rechazado ante un fallo de red
o si algo impidió completar la solicitud.
• Por defecto, fetch no enviará ni recibirá cookies del servidor, resultando en peticiones no
autenticadas si el sitio permite mantentener una sesión de usuario (para mandar
cookies, credentials de la opción init deberan ser configuradas). Desde el 25 de agosto de 2017. La
especificación cambió la politica por defecto de las credenciales a same-origin. Firefox cambió
desde la versión 61.0b13.
Una petición básica de fetch es realmente simple de realizar. Eche un vistazo al siguente código:
fetch('http://example.com/movies.json')
Aquí estamos recuperando un archivo JSON a través de red e imprimiendo en la consola. El uso
de fetch() más simple toma un argumento (la ruta del recurso que quieres obtener) y devuelve un
objeto Promise conteniendo la respuesta, un objeto Response.
Esto es, por supuesto, una respuesta HTTP no el archivo JSON. Para extraer el contenido en el
cuerpo del JSON desde la respuesta, usamos el método json() (definido en el mixin de Body, el cual
está implementado por los objetos Request y Response).
Nota: El mixin de Body tambien tiene metodos parecidos para extraer otros tipos de contenido del
cuerpo. Vease Body para más información.
Las peticiones de Fetch son controladas por la directiva de connect-src de Content Security
Policy en vez de la directiva de los recursos que se han devuelto.
Suministrando opciones de petición
El método fetch() puede aceptar opcionalmente un segundo parámetro, un objeto init que
permite controlar un numero de diferentes ajustes:
Vea fetch() (en-US), para ver todas las opciones disponibles y más detalles.
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
});
return response.json(); // parses JSON response into native JavaScript objects
postData('https://example.com/answer', { answer: 42 })
.then(data => {
});
Tenga en cuenta que mode: "no-cors" solo permite un conjunto limitado de encabezados en la
solicitud:
• Accept
• Accept-Language
• Content-Language
• Content-Type with a value of application/x-www-form-urlencoded, multipart/form-data,
or text/plain
fetch('flores.jpg').then(function(response) {
if(response.ok) {
response.blob().then(function(miBlob) {
miImagen.src = objectURL;
});to Clipboard
Copy
} else {
})
.catch(function(error) {
});
headers: myHeaders,
mode: 'cors',
cache: 'default' };
.then(function(response) {
return response.blob();
})
.then(function(myBlob) {
myImage.src = objectURL;
});
Request() acepta exactamente los mismos parámetros que el método fetch(). Puedes incluso pasar
un objeto de petición existente para crear una copia del mismo:
Esto es muy útil ya que el cuerpo de las solicitudes y respuestas son de un sólo uso. Haciendo una
copia como esta te permite utilizar la petición/respuesta de nuevo, y al mismo tiempo, si lo deseas,
modificar las opciones de init. La copia debe estar hecha antes de la lectura del <body>, y leyendo
el <body> en la copia, se marcará como leido en la petición original.
Nota: Existe también un método clone() (en-US) que crea una copia. Este tiene una semántica
ligeramente distinta al otro método de copia — el primero fallará si el cuerpo de la petición anterior
ya ha sido leído (lo mismo para copiar una respuesta), mientras que clone() no.
Enviar una petición con credenciales incluido
Para producir que los navegadores envien una petición con las credenciales incluidas, incluso para
una llamada de origen cruzado, añadimos credentials: 'include' en el el objeto init que se pasa al
método fetch().
fetch('https://example.com', {
credentials: 'include'
})
Si solotoquieres
Copy Clipboard
enviar la credenciales si la URL de la petición está en el mismo origen desde donde
se llamada el script, añade credentials: 'same-origin'.
fetch('https://example.com', {
credentials: 'same-origin'
})
Sin embargo para asegurarte que el navegador no incluye las credenciales en la petición,
usa credentials: 'omit'.
fetch('https://example.com', {
credentials: 'omit'
})
fetch(url, {
headers:{
Copy'Content-Type':
to Clipboard 'application/json'
Enviando un archivo
Los archivos pueden ser subido mediante el HTML de un elemento input <input type="file"
/>, FormData() (en-US) y fetch() (en-US).
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
fetch('https://example.com/profile/avatar', {
method: 'PUT',
body: formData
})
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.getAll("X-Custom-Header"));
Copy to Clipboard // ["ProcessThisImmediately",
"AnotherValue"]
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.getAll("X-Custom-Header")); // [ ]
Algunas de estas operaciones solo serán utiles en ServiceWorkers (en-US), pero estas disponen de
una mejor API para manipular headers.
try {
myResponse.headers.set("Origin", "http://mybank.com");
} catch(e) {
Un buen caso de uso para headers es comprobar cuando el tipo de contenido es correcto antes de
que se procese:
fetch(myRequest).then(function(response) {
return response.json().then(function(json) {
} else {
});
Guarda (Guard)
Desde que las cabeceras pueden ser enviadas en peticiones y recibidas en respuestas, y tienen
limitaciones sobre que información puede y debería ser mutable, los objeto headers tienen una
propierdad de guarda. Este no está expuesto a la Web, pero puede afectar a que operaciones de
mutación son permitidas sobre el objeto headers.
• Response.status — Entero (por defecto con valor 200) que contiene el código de estado de
las respuesta.
• Response.statusText (en-US) — Cadena (con valor por defecto "OK"), el cual corresponde
al mensaje del estado de código HTTP.
•
Copy toResponse.ok
Clipboard — Visto en uso anteriormente, es una clave para comprobar que el estado está
dentro del rango 200-299 (ambos incluidos). Este devuelve un valor Boolean (en-US), siendo true si
lo anterior se cumple y false en otro caso.
Estos pueden también creados programáticamente a través de JavaScript, pero esto solamente es
realmete útil en ServiceWorkers (en-US), cuando pones un objeto response personalizado a una
respuesta recibida usando un método respondWith() (en-US):
addEventListener('fetch', function(event) {
event.respondWith(
new Response(myBody, {
})
);
});
Nota: El método estático error() (en-US) simplemente devuelve un error en la respuesta. De igual
manera que redirect() (en-US) devuelve una respuesta que resulta en un redirección a una URL
especificada. Estos son solo relevantes tambien a ServiceWorkers.
Body
Tanto las peticiones como las respuestas pueden contener datos body. Body es una instancia de
cualquiera de los siguientes tipos:
• ArrayBuffer (en-US)
• ArrayBufferView (en-US) (Uint8Array y amigos)
• Blob/File
• string
•
Copy toURLSearchParams
Clipboard
• FormData
El mixin de Body define los siguientes metodos para extraer un body (implementado
por Request and Response). Todas ellas devuelven una promesa que es eventualmente resuelta con
el contenido actual.
• arrayBuffer() (en-US)
• blob() (en-US)
• json()
• text() (en-US)
• formData()
Este hace uso de los datos no texttuales mucho mas facil que si fuera con XHR.
fetch("/login", {
method: "POST",
body: form
});
Detectar característica
Puedes comprobar si el navegador soporta la API de Fetch comprobando la existencia
de Headers, Request, Response o fetch() (en-US) sobre el ámbito de Window o Worker. Por
ejemplo:
if (self.fetch) {
} else {
// do something with XMLHttpRequest?