1. Tout d’abord, examinons la structure des messages http.
1. Demander un message
Un message de requête HTTP se compose de quatre parties : ligne de requête, en-tête de requête, ligne vide et données de requête. La figure suivante montre le format général du message de requête.
(1) Ligne de demande
La ligne de requête se compose de trois champs : le champ de méthode de requête, le champ URL et le champ de version du protocole HTTP, qui sont séparés par des espaces. Par exemple, GET /index.html HTTP/1.1.
Les méthodes de requête du protocole HTTP incluent GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE et CONNECT. Nous présentons ici la méthode GET et la méthode POST les plus couramment utilisées.
GET : La méthode GET est utilisée lorsque le client souhaite lire un document depuis le serveur. La méthode GET nécessite que le serveur place la ressource localisée par l'URL dans la partie données du message de réponse et la renvoie au client. Lors de l'utilisation de la méthode GET, les paramètres de requête et les valeurs correspondantes sont ajoutés à l'URL. Un point d'interrogation ("?") est utilisé pour représenter la fin de l'URL et le début des paramètres de requête. les paramètres sont limités. Par exemple, /index.jsp?id=100&op=bind.
POST : La méthode POST peut être utilisée lorsque le client fournit de nombreuses informations au serveur. La méthode POST encapsule les paramètres de requête dans les données de requête HTTP, apparaissant sous forme de nom/valeur, et peut transmettre de grandes quantités de données.
(2)En-tête de demande
L'en-tête de la requête se compose de paires mot-clé/valeur, une paire par ligne, et les mots-clés et les valeurs sont séparés par deux points anglais ":". L'en-tête de requête informe le serveur de la requête du client. Les en-têtes de requête typiques sont :
Agent utilisateur : type de navigateur qui a généré la demande.
Accepter : Liste des types de contenus reconnus par le client.
Hôte : Le nom d'hôte demandé, permettant à plusieurs noms de domaine d'être à la même adresse IP, c'est-à-dire un hôte virtuel.
(3) Ligne vide
Le dernier en-tête de requête est suivi d'une ligne vide, des caractères de retour chariot et de saut de ligne sont envoyés pour informer le serveur qu'il n'y a plus d'en-tête de requête à suivre.
(4)Demander des données
Les données de la requête ne sont pas utilisées dans la méthode GET, mais dans la méthode POST. La méthode POST convient aux situations où les clients doivent remplir un formulaire. Les en-têtes de requête les plus couramment utilisés liés aux données de requête sont Content-Type et Content-Length.
2. Message de réponse
Le format du message de réponse est généralement similaire à celui du message de requête, sauf que la première ligne est différente. Les lecteurs peuvent trouver l'introduction à cet aspect sur Internet et n'entreront pas dans les détails ici.
2. Mise en œuvre du programme
Les étapes de mise en œuvre du programme sont les suivantes :
1. Recevez la demande du navigateur client ;
2. Créez un nouveau fil de discussion pour gérer la demande ;
3. Lisez les données du message, déterminez si le message est correct et analysez le contenu du message ;
4. Créez un message de réponse et envoyez-le au client ;
5. Terminez le fil de traitement et traitez les autres demandes des clients ;
Le code du programme est le suivant :
afficher la copie ordinaire dans le presse-papiers ?
importer java.net.* ;
importer java.io.* ;
importer java.util.* ;
importer java.lang.* ;
Serveur Web de classe publique {
public static void main(String [] arguments){
port international ;
ServerSocket serveur_socket ;
essayer{
port=Integer.parseInt(args[0]);
}
attraper (Exception e){
port=8080 ;
}
essayer{
server_socket=nouveau ServerSocket(port);
System.out.println("WebServer exécuté sur le port"+server_socket.getLocalPort());
tandis que(vrai){
Socket socket=server_socket.accept();
System.out.println("Nouvelle connexion acceptée"+socket.getInetAddress()+":"+socket.getPort());
//Créer un fil de discussion pour une requête spécifique afin de gérer la requête
essayer{
httpRequestHandler request=nouveau httpRequestHandler(socket);
Thread thread=nouveau Thread(requête);
thread.start();
}
attraper(Exception e){
System.out.println(e);
}
}
}
catch(IOException e){
System.out.println(e);
}
}
}
//Classe de thread pour le traitement des requêtes
la classe httpRequestHandler implémente Runnable{
chaîne statique finale CRLF="rn";
Prise de courant ;
Entrée InputStream ;
Sortie OutputStream ;
BufferedReader br;
// Détermine si le type de fichier demandé est correct
booléen fileType=true ;
//Paramètres d'initialisation
public httpRequestHandler (Socket socket) lève une exception {
this.socket=socket;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
//Démarre le fil
public void run(){
essayer{
processRequest();
}
attraper(Exception e){
System.out.println(e);
}
}
//Fonction principale pour le traitement des requêtes
private void processRequest() lève une exception{
tandis que(vrai){
Chaîne headerLine=br.readLine();
System.out.println("la demande du client est"+headerLine);
if(headerLine.equals(CRLF)||headerLine.equals(""))
casser;
StringTokenizer s=nouveau StringTokenizer(headerLine);
String temp=s.nextToken();
if(temp.equals("GET")){
String fileName=s.nextToken();
nomfichier="."+nomfichier ;
FileInputStream fis=null ;
booléen fileExists=true ;
if(!(fileName.endsWith(".htm")||fileName.endsWith(".html")))
{
this.fileType=false ;
essayer{
fis=new FileInputStream("erreur.html");
}
catch(FileNotFoundException e){
fileExists=false;
}
}
autre{
essayer{
fis=nouveau FileInputStream(fileName);
}
catch(FileNotFoundException e){
fileExists=false;
}
}
String serverLine="Serveur : un simple serveur Web Java" ;
Chaîne statusLine=null ;
Chaîne contentTypeLine=null ;
Chaîne EntityBody=null ;
Chaîne contentLengthLine="erreur";
if(fileExists&&this.fileType){
statusLine="HTTP/1.0 200 OK"+CRLF;
contentTypeLine="Content-type:"+this.contentType(fileName)+CRLF;
contentLengthLine="Content-Length:"+(new Integer(fis.available())).toString()+CRLF;
}
autre{
if(fileExists&&this.fileType==false){
statusLine="HTTP/1.0 400 BadRequest"+CRLF;
contentTypeLine="text/html";
EntityBody="<HTML>400 Pas BadRequest</TITLE></HEAD>"+
"<BODY>400 BadRequest"+
"<br>utilisation :http://votrenom d'hôte:port/"+
"nomFichier.html</BODY></HTML>";
}
sinon if(fileExists==false){
statusLine="HTTP/1.0 404 introuvable"+CRLF ;
contentTypeLine="text/html";
EntityBody="<HTML>404 introuvable</TITLE></HEAD>"+
"<BODY>404 introuvable"+
"<br>utilisation :http://votrenom d'hôte:port/"+
"nomFichier.html</BODY></HTML>";
}
}
sortie.write(statusLine.getBytes());
sortie.write(serverLine.getBytes());
sortie.write(contentTypeLine.getBytes());
sortie.write(contentLengthLine.getBytes());
sortie.write(CRLF.getBytes());
if(fileExists&&this.fileType){
sendBytes(fis,sortie);
fis.close();
}
autre{
sortie.write(entityBody.getBytes());
}
}
}
essayer{
sortie.close();
br.close();
socket.close();
}
attraper(Exception e){}
}
//Envoie la page demandée par le client
private static void sendBytes (FileInputStream fis, OutputStream os) lève une exception {
octet[] tampon=nouvel octet[1024];
int octets=0 ;
while((bytes=fis.read(buffer))!=-1){
os.write(tampon,0,octets);
}
}
//Définit le contenu de contentType
chaîne statique privée contentType (String fileName) {
if(fileName.endsWith(".htm")||fileName.endsWith(".html")){
renvoie "texte/html" ;
}
renvoie "nomfichier" ;
}