Diferència entre revisions de la pàgina «Comunitats, províncies, municipis. Migració a Node.js»

De wikijoan
Salta a la navegació Salta a la cerca
 
m
 
Línia 4: Línia 4:
 
=Referències=
 
=Referències=
 
Hem vist Node.js a teoria:
 
Hem vist Node.js a teoria:
*http://wiki.joanillo.org/index.php/Introducci%C3%B3_a_Node.js
+
*[[Introducció a Node.js]]
Durant el desenvolupament de la pràctica el professor s'ha trobat el típic problema de ''Control d'accés HTTP (CORS)'', que s'ha pogut solucionar fàcilment:
 
*https://stackoverflow.com/questions/18310394/no-access-control-allow-origin-node-apache-port-issue
 
  
 
=Desenvolupament=
 
=Desenvolupament=
Línia 12: Línia 10:
 
==Servidor http amb Node.js. Codi mínim==
 
==Servidor http amb Node.js. Codi mínim==
 
El codi mínim per accedir a la base de dades de municipis:
 
El codi mínim per accedir a la base de dades de municipis:
 
 
script '''node_http_server_simple.js''':
 
script '''node_http_server_simple.js''':
 
<pre>
 
<pre>
// el servidor web implementat amb node ha d'estar arrencat
+
//test:
// /home/joan/node-v9.6.1-linux-x64/bin/node /home/joan/M06_WEC_1718/html/UF4/municipis_node/node_http_server.js
 
// Are you running your script from the same directory you ran npm install mysql?
 
//important! npm install request
 
//important! npm install url
 
 
 
 
//http://localhost:8080/search_prov?id_com=2
 
//http://localhost:8080/search_prov?id_com=2
  
 
var http = require('http');
 
var http = require('http');
//var mysql = require('mysql');
+
var mysql = require('mysql2');
var mysql = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/mysql');
+
var request = require('request'); //npm install request
//var request = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/request');
+
var url = require('url'); //no cal instal·lar aquest mòdul
var request = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/request');
 
var url = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/url');
 
  
  
Línia 71: Línia 61:
 
Hem d'arrencar el servidor, i des del navegador web podem accedir a la informació de les províncies. Per ex:
 
Hem d'arrencar el servidor, i des del navegador web podem accedir a la informació de les províncies. Per ex:
 
*http://localhost:8080/search_prov?id_com=7
 
*http://localhost:8080/search_prov?id_com=7
Hem hagut d'instal.lar els paquets '''request''' i '''url''' per tal de poder accedir a la informació del paràmetre que passem per GET (''id_com=7)
+
Hem hagut d'instal·lar els paquets '''request''' i '''url''' per tal de poder accedir a la informació del paràmetre que passem per GET (''id_com=7)
 
<pre>
 
<pre>
 
$ npm install request
 
$ npm install request
 
$ npm install url
 
$ npm install url
</pre>
 
També hi ha hagut una mica d'embolic amb el directori on anem a busca els paquets ''npm''. Si el script que executem no està en el mateix directori que el binari ''node'' (d'on penja la carpeta ''node_modules/''), una possible solució (no òptima?) és posar la ruta on anem a buscar el paquet:
 
<pre>
 
var request = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/request');
 
var url = require('/home/joan/node-v9.6.1-linux-x64/bin/node_modules/url');
 
 
</pre>
 
</pre>
 
===Aplicació AJAX contra Node.js===
 
===Aplicació AJAX contra Node.js===
Línia 149: Línia 134:
 
   if (req.url.indexOf("comunitats")>=0) {
 
   if (req.url.indexOf("comunitats")>=0) {
 
     console.log("COMUNITATS");
 
     console.log("COMUNITATS");
    //https://stackoverflow.com/questions/18310394/no-access-control-allow-origin-node-apache-port-issue
 
    // Website you wish to allow to connect
 
    //res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080'); //no funciona?
 
 
     res.setHeader('Access-Control-Allow-Origin', '*'); //funciona
 
     res.setHeader('Access-Control-Allow-Origin', '*'); //funciona
    //res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // If needed
 
    //res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,contenttype'); // If needed
 
    //res.setHeader('Access-Control-Allow-Credentials', true); // If needed
 
  
 
     res.setHeader("Content-Type", "text/html; charset=utf-8");
 
     res.setHeader("Content-Type", "text/html; charset=utf-8");
Línia 166: Línia 145:
 
         for (var i = 0; i < rows.length; i++) {
 
         for (var i = 0; i < rows.length; i++) {
 
           console.log(rows[i].comunitat);
 
           console.log(rows[i].comunitat);
          //res.write(rows[i].comunitat + '<br />');
 
 
           res.write("<option value=\"" + rows[i].id_com + "\">" + rows[i].comunitat + "</option>");
 
           res.write("<option value=\"" + rows[i].id_com + "\">" + rows[i].comunitat + "</option>");
 
         };
 
         };
Línia 254: Línia 232:
 
==Solució==
 
==Solució==
 
Tens disponible el codi que s'ha comentat a classe, amb les tres versions:
 
Tens disponible el codi que s'ha comentat a classe, amb les tres versions:
*[[Fitxer:Municipis node.zip]] (actualitzat a 6 de març de 2019)
+
*[[Fitxer:Municipis node.zip]] (actualitzat a 22 de febrer de 2022)
  
 
=Entrega=
 
=Entrega=
Els alumnes entregaran al Classroom tots els fitxers generats (fitxers html). S'empaquetaran tots aquests fitxers i es pujaran al Schoology dins del termini d'entrega de la pràctica.
+
Entregaràs al Classroom tot el projecte empaquetat en un zip. Quan ho tinguis funcionant, ensenya-ho al professor, o sinó fes un screencast del funcionament de l'aplicatiu, comentant el resultat final i les parts més importants del codi.
 
 
Recorda la '''normativa''' per entregar les pràctiques al Schoology: [[ASIX-M10-UF2#Normativa_d.27entrega_de_les_pr.C3.A0ctiques_al_Schoology]]
 
  
{{Autor}}, febrer 2018
+
{{Autor}}, febrer 2022
[[Categoria: INS Jaume Balmes]]
 
[[Categoria: Assignatura DAW-M06-WEC]]
 

Revisió de 15:24, 22 feb 2022

Introducció

En la pràctica anterior has fet una mini-aplicació per navegar per les comunitats, províncies i municipis de l'EE. Anem ara a canviar la tecnologia del servidor, i anem a fer les nostres crides AJAX contra un servidor Node.js. És a dir, farem servir Javascript tan en el cantó del client com en el cantó del servidor.

Referències

Hem vist Node.js a teoria:

Desenvolupament

Servidor http amb Node.js. Codi mínim

El codi mínim per accedir a la base de dades de municipis: script node_http_server_simple.js:

//test:
//http://localhost:8080/search_prov?id_com=2

var http = require('http');
var mysql = require('mysql2');
var request = require('request'); //npm install request
var url = require('url'); //no cal instal·lar aquest mòdul


// Create a connection to MySql Server and Database
var connection = mysql.createConnection({
  host : 'localhost',
  port : 3306,
  database: 'municipis',
  user : 'alumne',
  password : 'keiL2lai',
  charset : 'utf8'
});


// Create a simple Web Server to respond to requests
http.createServer(function(req, res){
  // RECEIVED A REQUEST!
  console.log(req.url);

  res.setHeader("Content-Type", "text/html; charset=utf-8");
  res.writeHeader(200);

  var query = require('url').parse(req.url,true).query;
  var id_com = query.id_com;
  console.log(id_com);

  connection.query("SELECT id_prov,provincia from provincies where id_com="+id_com, function(err, rows){

  if(err != null) {
    res.end("Query error:" + err);
  } else {
    for (var i = 0; i < rows.length; i++) {
      console.log(rows[i].provincia);
      res.write(rows[i].provincia + '<br />');
    };
    res.end(""); //important
  }
});

}).listen(8080);

Hem d'arrencar el servidor, i des del navegador web podem accedir a la informació de les províncies. Per ex:

Hem hagut d'instal·lar els paquets request i url per tal de poder accedir a la informació del paràmetre que passem per GET (id_com=7)

$ npm install request
$ npm install url

Aplicació AJAX contra Node.js

Hem de modificar el nostre servidor per distingir si volem fer un llistat de les comunitats; volem llistar les províncies d'una comunitat; o volem llistar els municipis d'una província:

Ho farem mirant la url del request:

if (req.url.indexOf("comunitats")>=0) {
   console.log("COMUNITATS");
   ...
} else if (req.url.indexOf("search_prov")>=0) {
   console.log("PROVÍNCIES");
   ...
} else if (req.url.indexOf("search_mun")>=0) {
   console.log("MUNICIPIS");
   ...
}

Ara ja podem adaptar el codi que tenim de la pràctica anterior per fer crides contra el servidor http implementat amb Node.js. Per exemple, quan carreguem l'aplicació (body onload) carregarem en una select box la llista de totes les comunitats.

script index.html:

...
<script>
function carregar_comunitats()
{
	var xmlhttp;
	var txt_opcions_comunitats;
	xmlhttp=new XMLHttpRequest();
	xmlhttp.onreadystatechange=function()
	{
		if (xmlhttp.readyState==4 && xmlhttp.status==200)
		{
			txt_opcions_comunitats = xmlhttp.responseText;
			//alert(txt_opcions_comunitats);
			var comunitats = "";
			comunitats = "<select name=\"comunitat\" onchange=\"canvi_comunitat(this.value)\">";
			comunitats += txt_opcions_comunitats;
			comunitats += "</select>";

			document.getElementById('comunitats').innerHTML = comunitats;
		} else {
			document.getElementById('comunitats').innerHTML = "<img src=\"img/ajax_wait.gif\" />";
		}
	}
	xmlhttp.open("GET","http://localhost:8080/comunitats",true);
	xmlhttp.send();

}
...
</script>
...

I la cerca de les comunitats està implementada en el servidor Node.js de la següent manera:

node_http_server.js:

...
// Create a simple Web Server to respond to requests
http.createServer(function(req, res){
  // RECEIVED A REQUEST!
  console.log(req.url);

  if (req.url.indexOf("comunitats")>=0) {
    console.log("COMUNITATS");
    res.setHeader('Access-Control-Allow-Origin', '*'); //funciona

    res.setHeader("Content-Type", "text/html; charset=utf-8");
    res.writeHeader(200);
    connection.query("SELECT * from comunitats", function(err, rows){

      if(err != null) {
        res.end("Query error:" + err);
      } else {
        for (var i = 0; i < rows.length; i++) {
          console.log(rows[i].comunitat);
          res.write("<option value=\"" + rows[i].id_com + "\">" + rows[i].comunitat + "</option>");
        };
        res.end("");
      }

    });

  }

}).listen(8080);

Per tal de no tenir problemes amb l'origen del Request hem hagut de ficar la línia:

res.setHeader('Access-Control-Allow-Origin', '*');

Versions

v1.

  • NodeJS en el servidor. Des de NodeJS es fan els accessos a la base de dades de municipis. El servidor retorna al client una llista de comunitats/províncies/municipis separats amb caràcters delimitadors (això ho volem millorar en la següent versió).

v2.

  • Utilitzem la Fetch API per fer les crides asíncrones al servidor.
  • En el servidor (NodeJS) construïm una cadena amb format JSON que serà el format d'intercanvi amb el client (en la versió 3 això ho millorarem).

v3. Orientem el codi a POO

  • En el servidor (NodeJS) creem un objecte JSON de les comunitats/províncies/municipis, i ara el codi és més elegant (i menys procliu a errors de sintaxi). Però per enviar l'objecte JSON al client l'hem de convertir a cadena (JSON.stringify).
  • En el client creem les selects i options amb createElement i queda un codi més elegant (però potser més complicat).

v4.

En les versions anteriors hem fet un if dins el servidor NodeJS per saber si estem cercant les comunitats, províncies o municipis. Aquesta part la podem fer més elegant fent que el servidor node_http_server.js sigui més petit, i redirigint el codi als scripts comunitats.js, search_prov.js i search_mun.js, que tindran la lògica de connectar-se a la base de dades, cercar la informació que interessa, i construir l'objecte JSON que enviarem al client. Això ho aconseguim amb el següent codi mínim:

El servidor node http:

var http = require('http');
var url = require('url');

// Create a simple Web Server to respond to requests
http.createServer(function(req, res){
    console.log(req.url);
    var urlparsed = url.parse(req.url,true);
    console.log(urlparsed.pathname);
    if (urlparsed.pathname!="/favicon.ico"){
        var funct = require('.'+urlparsed.pathname);
        funct.main(req,res);
    }
// The server will be listen on port 8080 
}).listen(8080);

Si cridem a http://localhost:8080/comunitats_prova, aleshors la variable urlparsed.pathname valdrà /comunitats_prova (incloent la barra).

i el script comunitats_prova.js pot incloure el següent codi:

exports.main = function(req,res){
  console.log("COMUNITATS");
  res.end("Andalusia, Catalunya,...");
};

NOTA: tant se val cridar

com

El truco d'aquesta manera de fer és que els mòduls es poden exportar, i això ho fem amb les línies:

var funct = require('./comunitats');
funct.main(req,res);

i dins del codi de comunitats.js trobem la línia:

exports.main = function(req,res){
...

Al mètode main li podem posar el nom que vulguem, i podem tenir definits diferents mètodes.

Més informació:

Feina per l'alumne

Has d'adaptar l'aplicació de la pràctica anterior, que et permetia navegar per totes les comunitats, províncies i municipis, a la tecnologia Node.js en el servidor. Igual que hem vist en el codi de classe, has d'orientar el codi a JSON, a utilitzar objectes, i pots utilitzar la Fetch API en comptes de la forma més primitiva de fer les crides AJAX.

Tens una solució al final de la pràctica, però es recomana a l'alumne encaridament (encarecidamente en castellà) trobar una solució pròpia. En tot cas, i al final de tot, es pot consultar el codi proposat (que és el que s'ha vist a classe).

Solució

Tens disponible el codi que s'ha comentat a classe, amb les tres versions:

Entrega

Entregaràs al Classroom tot el projecte empaquetat en un zip. Quan ho tinguis funcionant, ensenya-ho al professor, o sinó fes un screencast del funcionament de l'aplicatiu, comentant el resultat final i les parts més importants del codi.


creat per Joan Quintana Compte, febrer 2022