1. Primero, echemos un vistazo a la estructura del mensaje de http.
1. Solicitar mensaje
Un mensaje de solicitud HTTP consta de cuatro partes: línea de solicitud, encabezado de solicitud, línea en blanco y datos de solicitud. La siguiente figura muestra el formato general del mensaje de solicitud.
(1) Línea de solicitud
La línea de solicitud consta de tres campos: el campo del método de solicitud, el campo de URL y el campo de versión del protocolo HTTP, que están separados por espacios. Por ejemplo, OBTENER /index.html HTTP/1.1.
Los métodos de solicitud del protocolo HTTP incluyen GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE y CONNECT. Aquí presentamos el método GET y el método POST más utilizados.
GET: El método GET se utiliza cuando el cliente quiere leer un documento del servidor. El método GET requiere que el servidor coloque el recurso ubicado en la URL en la parte de datos del mensaje de respuesta y lo envíe de regreso al cliente. Cuando se utiliza el método GET, los parámetros de solicitud y los valores correspondientes se agregan a la URL. Se utiliza un signo de interrogación ("?") para representar el final de la URL y el comienzo de los parámetros de solicitud. Los parámetros son limitados. Por ejemplo, /index.jsp?id=100&op=bind.
POST: El método POST se puede utilizar cuando el cliente proporciona mucha información al servidor. El método POST encapsula los parámetros de solicitud en datos de solicitud HTTP, que aparecen en forma de nombre/valor y puede transmitir grandes cantidades de datos.
(2)Encabezado de solicitud
El encabezado de la solicitud consta de pares de palabra clave/valor, un par por línea, y las palabras clave y los valores están separados por dos puntos en inglés ":". El encabezado de solicitud informa al servidor sobre la solicitud del cliente. Los encabezados de solicitud típicos son:
Agente de usuario: el tipo de navegador que generó la solicitud.
Aceptar: Lista de tipos de contenido reconocidos por el cliente.
Host: el nombre de host solicitado, que permite que varios nombres de dominio estén en la misma dirección IP, es decir, un host virtual.
(3) Línea en blanco
El último encabezado de solicitud va seguido de una línea en blanco, se envían caracteres de retorno de carro y avance de línea para notificar al servidor que no hay más encabezados de solicitud a seguir.
(4) Solicitar datos
Los datos de la solicitud no se utilizan en el método GET, sino en el método POST. El método POST es adecuado para situaciones en las que los clientes deben completar un formulario. Los encabezados de solicitud más utilizados relacionados con los datos de la solicitud son Content-Type y Content-Length.
2. Mensaje de respuesta
El formato del mensaje de respuesta es generalmente similar al mensaje de solicitud, excepto que la primera línea es diferente. Los lectores pueden encontrar la introducción a este aspecto en Internet y no entrarán en detalles aquí.
2. Implementación del programa
Los pasos para implementar el programa son los siguientes:
1. Recibir la solicitud del navegador del cliente;
2. Cree un nuevo hilo para manejar la solicitud;
3. Leer los datos del mensaje, determinar si el mensaje es correcto y analizar el contenido del mensaje;
4. Cree un mensaje de respuesta y envíelo al cliente;
5. Finalizar el hilo de procesamiento y procesar otras solicitudes de clientes;
El código del programa es el siguiente:
¿Ver copia simple en el portapapeles?
importar java.net.*;
importar java.io.*;
importar java.util.*;
importar java.lang.*;
Servidor web de clase pública {
principal vacío estático público (cadena [] argumentos) {
puerto internacional;
ServerSocket servidor_socket;
intentar{
puerto=Integer.parseInt(args[0]);
}
captura (Excepción e){
puerto=8080;
}
intentar{
server_socket=nuevo ServerSocket(puerto);
System.out.println("Servidor web ejecutándose en el puerto"+server_socket.getLocalPort());
mientras (verdadero) {
Zócalo zócalo=server_socket.accept();
System.out.println("Nueva conexión aceptada"+socket.getInetAddress()+":"+socket.getPort());
//Crea un hilo para una solicitud específica para manejar la solicitud
intentar{
solicitud httpRequestHandler = nuevo httpRequestHandler (socket);
Hilo hilo = nuevo hilo (solicitud);
hilo.start();
}
captura (Excepción e) {
System.out.println(e);
}
}
}
captura (IOException e) {
System.out.println(e);
}
}
}
//Clase de hilo para procesar solicitudes
la clase httpRequestHandler implementa Runnable{
Cadena estática final CRLF="rn";
Toma de corriente;
Entrada de flujo de entrada;
Salida de OutputStream;
BufferedReader br;
//Determinar si el tipo de archivo solicitado es correcto
tipo de archivo booleano = verdadero;
//Parámetros de inicialización
httpRequestHandler público (socket) lanza una excepción {
this.socket=socket;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
//Iniciamos el hilo
ejecución pública vacía(){
intentar{
solicitud de proceso();
}
captura (Excepción e) {
System.out.println(e);
}
}
//Función principal para procesar solicitudes
ProcessRequest nulo privado () lanza una excepción {
mientras (verdadero) {
Cadena headerLine=br.readLine();
System.out.println("la solicitud del cliente es"+headerLine);
if(encabezadoLine.equals(CRLF)||encabezadoLine.equals(""))
romper;
StringTokenizer s=new StringTokenizer(headerLine);
Cadena temp=s.nextToken();
si(temp.equals("OBTENER")){
String fileName=s.nextToken();
nombredearchivo="."+nombredearchivo;
FileInputStream fis=null;
archivo booleano existe = verdadero;
if(!(fileName.endsWith(".htm")||fileName.endsWith(".html")))
{
this.fileType=falso;
intentar{
fis=new FileInputStream("error.html");
}
captura(FileNotFoundException e){
fileExists=false;
}
}
demás{
intentar{
fis=new FileInputStream(nombredearchivo);
}
captura(FileNotFoundException e){
fileExists=false;
}
}
String serverLine="Servidor: un servidor web java simple";
Línea de estado de cadena = nulo;
Cadena contentTypeLine=null;
Cadena entidadCuerpo=nulo;
Cadena contentLengthLine="error";
if(fileExists&&this.fileType){
statusLine="HTTP/1.0 200 OK"+CRLF;
contentTypeLine="Tipo de contenido:"+this.contentType(fileName)+CRLF;
contentLengthLine="Contenido-Longitud:"+(new Integer(fis.available())).toString()+CRLF;
}
demás{
if(fileExists&&this.fileType==falso){
statusLine="HTTP/1.0 400 BadRequest"+CRLF;
contentTypeLine="texto/html";
entidadBody="<HTML>400 Solicitud no mala</TITLE></HEAD>"+
"<CUERPO>400 Solicitud Incorrecta"+
"<br>uso:http://tunombredehost:puerto/"+
"nombredearchivo.html</BODY></HTML>";
}
de lo contrario si(archivoExists==falso){
statusLine="HTTP/1.0 404 no encontrado"+CRLF;
contentTypeLine="texto/html";
entidadBody="<HTML>404 no encontrado</TITLE></HEAD>"+
"<CUERPO>404 No encontrado"+
"<br>uso:http://tunombredehost:puerto/"+
"nombredearchivo.html</BODY></HTML>";
}
}
salida.write(statusLine.getBytes());
salida.write(serverLine.getBytes());
salida.write(contentTypeLine.getBytes());
salida.write(contentLengthLine.getBytes());
salida.write(CRLF.getBytes());
if(fileExists&&this.fileType){
sendBytes(fis,salida);
fis.cerrar();
}
demás{
salida.write(entityBody.getBytes());
}
}
}
intentar{
salida.close();
br.cerrar();
socket.cerrar();
}
captura(Excepción e){}
}
//Enviar la pagina solicitada por el cliente
sendBytes vacío estático privado (FileInputStream fis, OutputStream os) arroja una excepción {
byte[] buffer=nuevo byte[1024];
bytes enteros = 0;
while((bytes=fis.read(búfer))!=-1){
os.write(búfer,0,bytes);
}
}
//Establece el contenido de contentType
tipo de contenido de cadena estática privada (nombre de archivo de cadena) {
if(nombredearchivo.endsWith(".htm")||nombredearchivo.endsWith(".html")){
devolver "texto/html";
}
devolver "nombre de archivo";
}