- How the Internet Works in 5 Minutes
- Internet es la
red de redes
. - Son muchos los factoes que intervienen en que internet funcione
- En su base tu ordenador (cliente) se comunica con otro ordenador (servidor)
- Y se establece un dialogo por pasos (peticion y respuesta)
Recursos
- How Does the Internet Actually Work?
- Inside a Google data center
- La HISTORIA de INTERNET #DiaDeInternet - Drawing Things
- How It Works: Internet of Things
Partes de una comunicación
Petición HTTP Típica
Respuesta HTTP Típica
HTTP y sus códigos Lista de respuestas HTTP
- Por tipología:
- 1xx Informativas
- 2xx Peticiones Correctas
- 3xx Redirecciones
- 4xx Errores Cliente
- 5xx Errores Servidor
Recursos
- HakTip - How to Capture Packets with Wireshark - Getting Started
- Are HTTP Websites Insecure?
- From July, Chrome will name and shame insecure HTTP websites
- Google Chrome: HTTPS or bust. Insecure HTTP D-Day is tomorrow, folks
- Steal My Login
- Google Chrome to Label Sites Using HTTP as Insecure Starting in July
- Firefox 59: mark HTTP as insecure
Recursos
Con Jquery
function peticionJqueryAjax (url) {
$.ajax({
dataType: "json",
url: url,
})
.done(function( data, textStatus, jqXHR ) {
console.log( "La solicitud se ha completado correctamente:", data );
})
.fail(function( jqXHR, textStatus, errorThrown ) {
console.log( "La solicitud a fallado:", textStatus);
});
}
peticionJqueryAjax ("<---URL---->");
Vanilla JS
- readyState:
- 0 es uninitialized
- 1 es loading
- 2 es loaded
- 3 es interactive
- 4 es complete
function peticionAjax(url) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
console.info(JSON.parse(xmlHttp.responseText));
} else if (xmlHttp.readyState === 4 && xmlHttp.status === 404) {
console.error("ERROR! 404");
console.info(JSON.parse(xmlHttp.responseText));
}
};
xmlHttp.open("GET", url, true);
xmlHttp.send();
}
peticionAjax("<---URL---->");
- Todo puede ser convertido a JSON y decodificado de vuelta
- Pero debe estar dentro de esta especificacion ECMA-404
JSON.parse()
: Analiza la cadena y retorna los valoresJSON.stringify()
: Analiza los valores y retorna una cadena
var dato = {
"nombre": "Ulises",
"Saludar": function () {console.log("Hola!")},
"profe": true,
"extras": undefined
}
var datoJSON = JSON.stringify(dato); //string -> "{"nombre":"Ulises","profe":true}"
var datoRecuperado = JSON.parse(datoJSON); //object -> {"nombre":"Ulises","profe":true}
Recursos
- JSON en Wikiwand
- MDN | JSON.parse()
- MDN | JSON.stringify()
- Validador: jsonformatter
- Visor: jsonviewer
APIs
Una API es una interfaz de programación de aplicaciones (del inglés API: Application Programming Interface). Es un conjunto de rutinas que provee acceso a funciones de un determinado software. Son publicadas por los constructores de software para permitir acceso a características de bajo nivel o propietarias, detallando solamente la forma en que cada rutina debe ser llevada a cabo y la funcionalidad que brinda, sin otorgar información acerca de cómo se lleva a cabo la tarea. Son utilizadas por los programadores para construir sus aplicaciones sin necesidad de volver a programar funciones ya hechas por otros, reutilizando código que se sabe que está probado y que funciona correctamente. Wikipedia
CRUD
En informática, CRUD es el acrónimo de "Crear, Leer, Actualizar y Borrar" (del original en inglés: Create, Read, Update and Delete), que se usa para referirse a las funciones básicas en bases de datos o la capa de persistencia en un software. Wikipedia
- Create:
- Method (POST):
- Respuesta 200 - OK
- Respuesta 204 - Sin contenido
- Respuesta 404 - No encontrado
- Respuesta 409 - Conflicto, ya existe
- Method (POST):
- Read:
- Method (GET):
- Respuesta 200 - OK
- Respuesta 404 - No encontrado
- Method (GET):
- Update:
- Method (PUT):
- Respuesta 200 - OK
- Respuesta 204 - Sin contenido
- Respuesta 404 - No encontrado
- Method (PUT):
- Delete:
- Method (DELETE):
- Respuesta 200 - OK
- Respuesta 404 - No encontrado
- Method (DELETE):
REST: Transferencia de Estado Representacional
La transferencia de estado representacional (en inglés representational state transfer) o REST es un estilo de arquitectura software para sistemas hipermedia distribuidos como la World Wide Web. El término se originó en el año 2000, en una tesis doctoral sobre la web escrita por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP y ha pasado a ser ampliamente utilizado por la comunidad de desarrollo. Wikipedia
APIs: Ejemplos de documentación
APIs: Listados
APIs: Interesantes
- Shodan
- pokeapi
- Open Weather Map
- Fitbit
- Marvel
- SWAPI - The Star Wars API
- Deck of Cards - API
- TheTVDB API v2
- Twitter Streaming
- Guild Wars 2
- Nutritionix API
El Intercambio de Recursos de Origen Cruzado (CORS) es un mecanismo que utiliza encabezados adicionales HTTP para permitir que un user agent obtenga permiso para acceder a recursos seleccionados desde un servidor, en un origen distinto (dominio), al que pertenece. Un agente crea una petición HTTP de origen cruzado cuando solicita un recurso desde un dominio distinto, un protocolo o un puerto diferente al del documento que lo generó. MDN
Recursos
- Understanding CORS
- CORS Wikiwand
- Tutorial CORS
- Using CORS by html5rocks
- Control de acceso HTTP (CORS) by MDN
- Cross-origin resource sharing en Wikipedia
- Enable cross-origin resource sharing
- crossorigin.me (Proxy)
Proxy Free Online
Nodejs
// Crea un fichero: server.js
// En la terminal: npm install express request && node server.js
var express = require('express');
var request = require('request');
var app = express();
var path = require('path');
// Static files
app.use(express.static('public'));
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/public/index.html'));
});
app.get('/proxy', function (req, res){
// @Example: localhost:8080/proxy?url=http://airemad.com/api/v1/station/
// CORS
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// PIPE Response
request({
url: req.query.url,
method: req.query.method || "GET"
}).pipe(res)
});
app.listen(8080);
- json (formato)
{ foo: 'bar' }
- callback (cliente)
mycallback = function(data){
alert(data.foo);
};
- peticion (cliente)
var url = "http://www.example.net/sample.aspx?callback=mycallback";
- respuesta (servidor)
mycallback({ foo: 'bar' });
- Ejemplo de CORS y JSONP con php de formandome
<?php
header('content-type: application/json; charset=utf-8');
header("access-control-allow-origin: *");
//Cadena de conexión:
$connect = mysql_connect("localhost", "usuario", "pwd")
or die('Could not connect: ' . mysql_error());
//seleccionamos bbdd:
$bool = mysql_select_db("database", $connect);
if ($bool === False){
print "No puedo encontrar la bbdd: $database";
}
//inicializamos el cliente en utf-8:
mysql_query('SET names utf8');
$query = "SELECT * FROM futbolistas";
$result = mysql_query($query) or die("SQL Error: " . mysql_error());
$data = array();
// obtenemos los datos:
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$data[] = array(
'id' => $row['id'],
'nombre' => $row['nombre'],
'apellido' => $row['apellido'],
'posicion' => $row['posicion'],
'equipo' => $row['equipo'],
'dorsal' => $row['dorsal'],
'desc' => $row['desc'],
'imagen' => $row['imagen']
);
}
//codificamos en json:
$json = json_encode($data);
//enviamos json o jsonp según venga o no una función de callback:
echo isset($_GET['callback'])
? "{$_GET['callback']}($json)"
: $json;
?>
- Ejemplo con Nodejs
var express = require('express');
var app = express();
app.get('/endpointJSON', function(req, res){
console.log('JSON response');
console.log(req.query);
res.json(req.query);
});
app.listen(3000);
Soporte en cliente (librerías):
- Jquery:
// Using YQL and JSONP $.ajax({ url: "http://query.yahooapis.com/v1/public/yql", jsonp: "callback", dataType: "jsonp", data: { q: "select title,abstract,url from search.news where query=\"cat\"", format: "json" }, success: function( response ) { console.log( response ); // server response } });
Librerías
Recursos
- Is JSONP safe to use?
- Using JSONP Safely
- Practical JSONP Injection
- JSONP for cross-site Callbacks
- (in)Security of JSONP: CSRF risks
JSON remplazando formularios
<form action="/action_page.php" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="name" placeholder="First name">
<input type="submit" value="Enviar">
</form>
var nombreDato = 'Yo mismo';
var xhr = new XMLHttpRequest();
xhr.open('POST', '/action_page.php');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
if (xhr.status === 200 && xhr.responseText !== nombreDato) {
console.log('Todo bien! Respuesta:', xhr.responseText);
}
else if (xhr.status !== 200) {
console.log('Algo va mal. Codigo de estado:', xhr.status);
}
};
xhr.send(encodeURI('name=' + nombreDato));
Mandar un JSON limpio vía POST
var nombreDato = 'Yo mismo';
var xhr = new XMLHttpRequest();
xhr.open('POST', '/action_page.php');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status === 200) {
console.log("respuesta:", JSON.parse(xhr.responseText));
}
};
xhr.send(JSON.stringify({
"name": nombreDato
}));
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://someotherdomain.com');
xhr.withCredentials = true; // Cookies
xhr.setRequestHeader('Content-Type', 'text/plain'); // header personal
xhr.onload = function() {
if (xhr.status === 200) {
console.log("respuesta:", JSON.parse(xhr.responseText));
}
};
xhr.send('sometext');
Recursos
- XMLHttpRequest.withCredentials
- XMLHttpRequest.setRequestHeader()
- Forbidden response header name
- Forbidden header name
Ejemplo sencillo
var formData = new FormData();
formData.append("usuario", "Ulises");
formData.append("id", 123456); // todo se convierte a String
// Contenido desde un <input type="file"> desde el HTML
formData.append("fichero1", fileInputElement.files[0]);
// Fichero creado al vuelo con JavaScript
var content = '<a id="a"><b id="b">hey!</b></a>'; // El contenido del nuevo fichero
var blob = new Blob([content], { type: "text/xml"});
formData.append("otro_fichero", blob);
var request = new XMLHttpRequest();
request.open("POST", "http://myserver.com/submitData");
request.send(formData);
Ejemplo partiendo de un formulario existente
// Trae el formulario del HTML
var formElement = document.getElementById("myFormElement");
formData = new FormData(formElement);
//Añade más información
formData.append("serialnumber", serialNumber++);
//Enviando los datos...
var request = new XMLHttpRequest();
request.open("POST", "http://myserver.com/submitData");
request.send(formData);
Recursos
Usando eventos y más...
var request = new XMLHttpRequest();
// Seleccionamos un fichero para subir
data.append('file', document.querySelector('#upload-file').files[0]);
request.addEventListener('load', function(e) {
console.log("Content-Type:", request.getResponseHeader("Content-Type"))
console.log(request.response);
});
// Gestión del progreso de subida....
request.upload.addEventListener('progress', function(e) {
var percent_complete = (e.loaded / e.total)*100;
console.log("Llevamos un", percent_complete+"%");
});
// Ajustamos la respuesta del servidor a fichero json, evitando la codificación errónea
request.responseType = 'json';
request.open('post', 'upload.php');
request.send(data);
Abortar la carga
var xhr = new XMLHttpRequest(),
method = "GET",
url = "https://fictizia.com/";
xhr.open(method, url, true);
xhr.send();
if (condicion) {
xhr.abort();
}
Un mundo de posibilidades...
- XMLHttpRequest.responseXML
- XMLHttpRequest.responseType
- XMLHttpRequest.upload
- XMLHttpRequest.timeout
- XMLHttpRequest.getAllResponseHeaders()
- XMLHttpRequest.getResponseHeader()
- XMLHttpRequest.overrideMimeType()
// service.com/hacked
// {data:"<script>alert("¡Sorpresa!")</script>"}
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://service.com/hacked');
xhr.onload = function() {
if (xhr.status === 200) {
var respuesta = JSON.parse(xhr.responseText)
console.log("respuesta:", respuesta);
document.body.innerHtml = respuesta.data
}
};
xhr.send();
Normas básicas
- Usar
innerText
y noinnerHtml
- Nunca jamas usar
eval
- Nunca encriptar en cliente
- No confies en la lógica del front
Recursos
- Is Your Website Hackable?
- AJAX Security Cheat Sheet
- Testing for AJAX Vulnerabilities (OWASP-AJ-001)
- Understanding Ajax vulnerabilities
- Portal de datos abiertos del Ayuntamiento de Madrid
- Iniciativa de datos abiertos del Gobierno de España
- EMT Datos Abiertos
- European Data Portal
- Open NASA
- Datos Abiertos de Mexico
- The home of the U.S. Government’s open data
- Compatibilidad nula con IE11
- Se hace uso de promesas y se puede escalar con Async/Await
- Puede gestionar llamadas sin soporte a CORS
- Las peticiones no pueden ser paradas
GET básico
function ajaxHandler (url, cb){
fetch(url)
.then(function(response) {
return response.json();
})
.then(function(data) {
cb(data)
})
.catch(function(error) {
console.log(error)
});
}
ajaxHandler("http://airemad.com/api/v1/station", function(data){
console.log("Data:", data)
})
Multimedia
var myImage = document.querySelector('.my-image');
fetch('flowers.jpg').then(function(response) {
return response.blob();
}).then(function(blob) {
var objectURL = URL.createObjectURL(blob);
myImage.src = objectURL;
});
La mágia es Request
var request = new Request('http://fictizia.com/subir', {
method: 'POST',
mode: 'no-cors',
redirect: 'follow',
headers: new Headers({
'Content-Type': 'text/plain',
'X-My-Custom-Header': 'CustomValue'
})
});
fetch(request).then(function() { //Gestión de la respuesta });
Subir los datos de un formulario
fetch('https://davidwalsh.name/submit', {
method: 'post',
body: new FormData(document.getElementById('comment-form'))
});
Documentacion
- Response()
- Response.redirected
- Response.clone()
- Response.status
- Response.statusText
- Response.type
- Response.headers
- Body.bodyUsed
- Body.body
- Body.text()
- Body.json()
- Body.formData()
- Body.blob()
- Body.arrayBuffer()
- Response.ok
- Response.error()
Recursos
- Fetch API by DWB
- Introduction to fetch() By Matt Gaunt
- This API is so Fetching! by Mozilla Hacks
- That's so fetch! by Jake Archibald
- Can I use? Fetch
- Basics: Using AJAX with Fetch API
- Fetch: Polyfill
1 - Sacar en el html los datos de polen.
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var datos = (JSON.parse(xmlHttp.responseText));
var contenido = "";
datos.forEach(function(estacion) {
contenido += "<h1>" + estacion.name + " (" + estacion.id + ")</h1>"
contenido += "<ul>"
for (var medicion in estacion.mediciones) {
contenido += "<li>" + medicion + ": <i>" + estacion.mediciones[medicion]["resumen"] + "</i></li>"
}
contenido += "</ul>"
})
document.body.innerHTML = contenido;
} else if (xmlHttp.readyState === 4 && xmlHttp.status === 404) {
console.error("ERROR! 404");
console.info(JSON.parse(xmlHttp.responseText));
}
};
xmlHttp.open("GET", "http://airemad.com/api/v1/pollen", true);
xmlHttp.send();
2 - Sacar en el html el tiempo meteorológico de Madrid, Barcelona y Valencia. Nota: http://openweathermap.org te será de gran ayuda, busca la solución al error 401
var contenido = "";
function temperaturaCiudad (ciudad) {
var xmlHttp = new XMLHttpRequest(),
APIKey = '', // Puedes usar una cuenta gratuita -> http://openweathermap.org/price
cURL = 'http://api.openweathermap.org/data/2.5/weather?q='+ciudad+'&APPID='+APIKey;
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var datos = (JSON.parse(xmlHttp.responseText));
contenido += "<h1>"+datos.name+"</h1>"
contenido += "<p>"+datos.weather[0].description+"</p>"
document.body.innerHTML = contenido;
} else if (xmlHttp.readyState === 4 && xmlHttp.status === 404) {
datos = JSON.parse(xmlHttp.responseText);
console.error("ERROR! 404");
console.info(datos);
}
};
xmlHttp.open( "GET", cURL, true );
xmlHttp.send();
}
temperaturaCiudad("Madrid");
temperaturaCiudad("Barcelona");
temperaturaCiudad("Valencia");
3 - Jugando con datos abiertos, saquemos los detalles de todos los cuadros eléctricos de Gijón por consola.
function peticionAjax (url) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var datos = (JSON.parse(xmlHttp.responseText));
console.log(datos)
} else if (xmlHttp.readyState === 4 && xmlHttp.status === 404) {
console.error("ERROR! 404");
console.info(JSON.parse(xmlHttp.responseText));
}
};
xmlHttp.open( "GET", url, true );
xmlHttp.send();
}
peticionAjax("http://opendata.gijon.es/descargar.php?id=163&tipo=JSON");
// Podemos encontrar errores en las respuestas.
// cuadromando[5] ...
calle: "Faustina Álvarez García"
latitud: 43.526376045
longitud: -5.685764873
numero: ""
potencia_w_: 17321
// ...