Tutoriel : serveur Web en Java

Vous l'avez déjà

... en toute indépendance des serveurs professionnels comme Tomcat, Jetty, etc., ou des solutions pédagogiques ab ovo.

Un micro-serveur Web fait partie de la distribution standard de Java (com.sun.net.httpserver; le domaine com.sun. ..., contrairement à sun. ... est une contribution publique, stable et documentée de Oracle à la communauté Java). Pour des tests superficiels il suffit de l'emballer en une structure exécutable et tester. Et ensuite développer des détails... [[Il faut que vous sachiez que les serveurs Web de ce genre sont disponible aussi dans d'autres langages, et souvent considérablement plus faciles à utiliser : en Python ou en JavaScript...]]

Voici la création d'un serveur qui peut être testé tout de suite par http://localhost:8600/MonServeur. Il peut être compilé par javac dans n'importe quel dossier, qui sera sa racine.

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Serv {
  public static void main(String[] args) throws Exception {
    HttpServer server = HttpServer.create(new InetSocketAddress(8600), 0);
    server.createContext("/MonServeur", new MyHandler());
    server.setExecutor(null); // exécuteur par défaut
    System.out.println("Serveur init.");  // Pour signaler
    server.start(); }

  static class MyHandler implements HttpHandler {
    public void handle(HttpExchange t) throws IOException {
      String response = "<h2>La solution est connue : 42.</h2>";
      t.sendResponseHeaders(200, response.length()); // Ou 0 (zéro); contenu en morceaux
      OutputStream os = t.getResponseBody();
      os.write(response.getBytes());
      os.close();
    }
}}

Ce serveur avec sa paramétrisation minimale, retourne un simple texte HTML, et si vous avez besoin d'autre chose, formatez la réponse vous-même. Sa fonctionnalité se réduit à la mise en écoute (TCP) et la préparation de l'entête de la réponse HTTP. Il démarre dans un thread séparé, la gestion des tâches (Runnable) est facilitée grâce aux Exécuteurs. Le serveur est de bas niveau, on voit que la réponse est formatée comme un tableau d'octets. (Et si vous ne savez pas à quoi correspond la réponse "42", il vous faudra compléter votre culture littéraire...)

Le paramètre HttpExchange t permet l'envoi de la réponse, mais aussi de récupérer la requête. Voici comment récupérer le chemin d'accès et la requête GET :

...
import java.net.*; // Pour URI
// dans handle(...)
  URI uri = t.getRequestURI();
  String ph = uri.getPath()
  String qr = uri.getQuery();
et si on accède à localhost:8600/MonServeur/docum.html?par1=val11&par2=val22, les chaînes récupérées ph et qr sont : /MonServeur/docum.html et par1=val11&par2=val22 . Vous pouvez décortiquer les éléments, et trouver d'autres informations par vos soins : l'agent client, les paramètres de la connexion... L'interface HttpHandler est assez universelle.

Il y a un peu plus de documentation/exemples ici, ici ou ici, pour voir comment gérér les paramètres GET.


On peut partir d'un niveau encore plus bas.

Les solutions de ce genre sont construites d'habitude pour l'apprentissage, ou pour l'intégration du serveur dans une autre application, communiquant par de différents protocoles.

Parmi une multitude de solutions, voici le code de Paul Mutton (jibble.org), disponible déjà compilé, et avec les sources. Vous y trouverez le code permettant de résoudre l'exercice 3 (la présentation des répertoires et des fichiers). La totalité du code se réduit à deux fichiers, un définit le serveur, l'autre gère les threads et les handlers, au total moins de 200 lignes de code. Téléchargez la version "full" avec les sources, pour les lire, et la version compilée, pour la tester localement.

Si un jour vous êtes tentés par la construction manuelle d'un serveur de très bas niveau, vous allez construire le code genre :

serverSocket =  
 new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
qui créé votre portail d'écoute. Ensuite il faut entrer dans une boucle :
while (marche_encore) {
  Socket socket = null; // le client
  InputStream input = null;
  ...
  try {socket = serverSocket.accept();  // Attente. Le client est-il là?
       input = socket.getInputStream(); // OK, on lit la requête.
       ...
  } ... // la communication peut échouer...
Plus d'information vous trouverez ici.

Et encore des réalisations dignes d'intérêt

La construction des serveurs spécialisés (et pas trop), et des boîtes d'outils pour l'assemblage des serveurs continue et s'intensifie. On en a besoin pour plusieurs projets : – tout ceci a besoin de solutions spécifiques, avec des règles de sécurité parfois très particulières, et des protocoles non-universels. Il faut obligatoirement faire tout depuis des sources, maîtrisées à 100%.

Voici l'adresse du "Simple Framework", un projet qui – comme la machinerie com.sun, n'est pas un serveur prêt à l'usage, mais un framework, facilitant la construction des serveurs dédiés (par ex. pour les jeux ; ceci a déjà été fait). Ceci est un projet compliqué, sa documentation est abondante, même si le paquet téléchargeable est minuscule, 1M, avec la documentation, sources et tests.

Un autre, Tiny Java Web Server, pas si "tiny" (paquet de 7M)..., mais considérablement plus compact que Jetty (sans parler de Tomcat). Il est capable de fonctionner comme un conteneur Web (pas seulement un httpd), et il est adapté à Android (Dalvik). C'est un projet qui évolue lentement, car il est essentiellement l'oeuvre d'une seule personne, Dmitriy Rogatkin.


Retour aux exercices
Retour à l'accueil