La plupart de ces opérations sont invisibles pour l'internautes, voire même pour le développeur. Par contre il peut être utile de savoir ce qui se cache derrière les communications entre un client et un serveur.
Envoi et reception de données avec la Class HttpRawSocket
Contrairement à HttpURLConnection, la class est un wrapper minimaliste de l'objet JAVA socket. Les fonctions implémentées servent à couvrir les requêtes courantes:- connect(): se connecter puis receptionner la réponse,
- setUserAgent(): fixer le UserAgent, car certains serveurs bloquent s'il n'est pas défini,
- setEncoding(): demander la compression gzip de la page,
- getHeader(): retourne l'entete de la page HTML,
- getHtml(): retourne le code source de la page.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Communiquer directement avec un socket
* @author Fobec 2013
* @see http://www.fobec.com/java/1130/communiquer-directement-avec-socket.html
*/
public class HttpRawSocket {
private String request = ""; //commande envoye
private String header=""; //reponse header
private String html=""; //reponse html
private String ua = null; //user agent
private boolean gzip=false; //compression demande
/**
* Ouvrir un socket et envoyer une commande
* @param aURL
* @throws MalformedURLException
* @throws IOException
*/
public void connect(String aURL) throws MalformedURLException, IOException {
Socket socket = new Socket();
URL url = new URL(aURL);
socket.connect(new InetSocketAddress(url.getHost(), 80));
try {
InputStreamReader inputreader=new InputStreamReader(socket.getInputStream());
BufferedReader reader = new BufferedReader(inputreader);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
//envoyer la requete
this.request=this.buildCommand(url);
writer.println(this.request);
//receptionner la réponse
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line).append(System.getProperty("line.separator"));
}
//Séparer le header du code html
String response = sb.toString();
String tag=System.getProperty("line.separator")+System.getProperty("line.separator");
int idx=response.indexOf(tag);
this.header = response.substring(0,idx);
this.html = response.substring(idx+1);
} finally {
socket.close();
}
}
/**
* Fixer le UserAgent
* @param useragent
*/
public void setUserAgent(String useragent) {
this.ua = useragent;
}
//Fixer la compression
public void setEncoding(boolean acceptGzip) {
this.gzip = acceptGzip;
}
//Retourner la requete envoyé au serveur
public String getRequest() {
return this.request;
}
//Retourner le header de la réponse
public String getHeader() {
return this.header;
}
//retourner le code html
public String getHtml() {
return this.html;
}
/**
* Assembler la requete à envoyer au serveur
* @param url
* @return
*/
private String buildCommand(URL url) {
String cmd = "GET " + url.getPath() + " HTTP/1.1rn";
cmd += "Host: " + url.getHost() + "rn";
if (this.ua != null) {
cmd += "User-Agent: "+this.ua+"rn";
}
if (this.gzip == true) {
cmd += "Accept-Encoding: gzip, deflatern";
}
//Close
cmd+="rn";
return cmd;
}
}
Charger une page internet avec les sockets
Au delà de l'aspect pédagogique, la class a pour but de charger rapidement des pages HTML en recueillant le maximum d'information sur la communication avec le serveur web. Pour l'exemple, nous allons nous connecter au serveur d'Ubuntu.org et charger la page HTML de téléchargement de ubuntu.
public class HttpRawSocket {
public static void main(String[] args) {
HttpRawSocket httpSocket = new HttpRawSocket();
try {
httpSocket.setUserAgent("Exemple java de Fobec.com");
httpSocket.connect("http://ubuntu-fr.org/telechargement");
System.out.println(httpSocket.getRequest());
System.out.println(httpSocket.getHeader());
System.out.println(httpSocket.getHtml());
} catch (MalformedURLException ex) {
Logger.getLogger(HttpRawSocket.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(HttpRawSocket.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
La requête envoyée au serveur
GET /telechargement HTTP/1.1
Host: ubuntu-fr.org
User-Agent: Exemple java de Fobec.com
Host: ubuntu-fr.org
User-Agent: Exemple java de Fobec.com
La commande GET indique que l'on souhaite receptionner des données. Pour l'envoi d'un formulaire, nous aurions utiliser un POST.
L'entête de la réponse
HTTP/1.0 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 23 Jul 2013 15:05:15 +0000
ETag: "1374591915"
Content-Language: en
X-Generator: Drupal 7 (http://drupal.org)
Link: </telechargement>; rel="canonical",</node/14>; rel="shortlink"
Content-Length: 13978
Date: Tue, 23 Jul 2013 15:05:15 GMT
Age: 0
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Cache: MISS from ipcop.localdomain
Via: 1.0 ipcop.localdomain:800 (squid/2.6.STABLE21)
Connection: close
Server: nginx
Content-Type: text/html; charset=utf-8
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 23 Jul 2013 15:05:15 +0000
ETag: "1374591915"
Content-Language: en
X-Generator: Drupal 7 (http://drupal.org)
Link: </telechargement>; rel="canonical",</node/14>; rel="shortlink"
Content-Length: 13978
Date: Tue, 23 Jul 2013 15:05:15 GMT
Age: 0
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Cache: MISS from ipcop.localdomain
Via: 1.0 ipcop.localdomain:800 (squid/2.6.STABLE21)
Connection: close
Le plus important est la mention 200 tout s'est bien passé !!!
Le code HTML renvoyé
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
"http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" version="XHTML+RDFa 1.0" dir="ltr"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/terms/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:og="http://ogp.me/ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:sioc="http://rdfs.org/sioc/ns#"
xmlns:sioct="http://rdfs.org/sioc/types#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
<head profile="http://www.w3.org/1999/xhtml/vocab">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
....
"http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" version="XHTML+RDFa 1.0" dir="ltr"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/terms/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:og="http://ogp.me/ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:sioc="http://rdfs.org/sioc/ns#"
xmlns:sioct="http://rdfs.org/sioc/types#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
<head profile="http://www.w3.org/1999/xhtml/vocab">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
....
Voici le code HTML qui sera affiché dans un navigateur internet par exemple.