1. Во-первых, давайте посмотрим на структуру сообщений http.
1. Запросить сообщение
Сообщение HTTP-запроса состоит из четырех частей: строки запроса, заголовка запроса, пустой строки и данных запроса. На следующем рисунке показан общий формат сообщения запроса.
(1) Строка запроса
Строка запроса состоит из трёх полей: поля метода запроса, поля URL и поля версии протокола HTTP, которые разделены пробелами. Например, GET /index.html HTTP/1.1.
Методы запроса протокола HTTP включают GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE и CONNECT. Здесь мы представляем наиболее часто используемые методы GET и POST.
GET: метод GET используется, когда клиент хочет прочитать документ с сервера. Метод GET требует, чтобы сервер поместил ресурс, расположенный по URL-адресу, в часть данных ответного сообщения и отправил его обратно клиенту. При использовании метода GET параметры запроса и соответствующие значения добавляются к URL-адресу. Знак вопроса («?») используется для обозначения конца URL-адреса и начала длины передаваемых параметров запроса. параметры ограничены. Например, /index.jsp?id=100&op=bind.
POST: метод POST можно использовать, когда клиент предоставляет серверу большой объем информации. Метод POST инкапсулирует параметры запроса в данные HTTP-запроса, представленные в форме имени/значения, и может передавать большие объемы данных.
(2) Заголовок запроса
Заголовок запроса состоит из пар ключевое слово/значение, по одной паре в строке, причем ключевые слова и значения разделяются английским двоеточием «:». Заголовок запроса информирует сервер о запросе клиента. Типичные заголовки запроса:
User-Agent: тип браузера, сгенерировавшего запрос.
Принять: список типов контента, распознаваемых клиентом.
Хост: запрошенное имя хоста, позволяющее нескольким доменным именам находиться на одном IP-адресе, то есть виртуальном хосте.
(3) Пустая строка
За последним заголовком запроса следует пустая строка, символы возврата каретки и перевода строки отправляются для уведомления сервера о том, что заголовков запроса больше нет.
(4) Запросить данные
Данные запроса используются не в методе GET, а в методе POST. Метод POST подходит для ситуаций, когда клиентам необходимо заполнить форму. Наиболее часто используемые заголовки запроса, связанные с данными запроса, — это Content-Type и Content-Length.
2. Ответное сообщение
Формат ответного сообщения в целом аналогичен сообщению-запросу, за исключением того, что первая строка отличается. Читатели могут найти введение в этот аспект в Интернете и не будут здесь вдаваться в подробности.
2. Реализация программы
Шаги по реализации программы следующие:
1. Получите запрос от клиентского браузера;
2. Создайте новый поток для обработки запроса;
3. Прочитайте данные сообщения, определите правильность сообщения и проанализируйте его содержимое;
4. Создайте ответное сообщение и отправьте его клиенту;
5. Завершить поток обработки и обработать другие запросы клиентов;
Код программы следующий:
просмотреть обычную копию в буфер обмена, распечатать?
импортировать java.net.*;
импортировать java.io.*;
импортировать java.util.*;
импортировать java.lang.*;
публичный класс WebServer {
public static void main(String [] args){
внутренний порт;
ServerSocket server_socket;
пытаться{
порт = Integer.parseInt(args[0]);
}
поймать (Исключение е) {
порт = 8080;
}
пытаться{
server_socket = новый ServerSocket (порт);
System.out.println("Веб-сервер работает на порту"+server_socket.getLocalPort());
пока (правда) {
Сокет сокета = server_socket.accept();
System.out.println("Новое соединение принято"+socket.getInetAddress()+":"+socket.getPort());
//Создаем поток для конкретного запроса для обработки запроса
пытаться{
httpRequestHandler запрос = новый httpRequestHandler (сокет);
Поток потока = новый поток (запрос);
поток.start();
}
поймать (Исключение е) {
System.out.println(e);
}
}
}
поймать (IOException е) {
System.out.println(e);
}
}
}
//Класс потока для обработки запросов
класс httpRequestHandler реализует Runnable{
конечная статическая строка CRLF="rn";
Розетка розетка;
Входной поток ввода;
Выходной поток вывода;
BufferedReader бр;
//Определяем, правильный ли запрошенный тип файла
логический fileType = true;
//Параметры инициализации
public httpRequestHandler (сокет сокета) выдает исключение {
this.socket=сокет;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=new BufferedReader(новый InputStreamReader(socket.getInputStream()));
}
//Запускаем поток
общественный недействительный запуск () {
пытаться{
процессЗапрос();
}
поймать (Исключение е) {
System.out.println(e);
}
}
//Основная функция обработки запросов
Private void ProcessRequest() выдает исключение {
пока (правда) {
Строка headerLine=br.readLine();
System.out.println("клиентский запрос"+headerLine);
if(headerLine.equals(CRLF)||headerLine.equals(""))
перерыв;
StringTokenizer s = новый StringTokenizer (headerLine);
Строка temp=s.nextToken();
if(temp.equals("GET")){
Строка fileName=s.nextToken();
имя_файла="."+имя_файла;
FileInputStream фис = ноль;
логическое fileExists = true;
if(!(fileName.endsWith(".htm")||fileName.endsWith(".html")))
{
this.fileType=false;
пытаться{
fis=new FileInputStream("error.html");
}
catch (FileNotFoundException е) {
fileExists = ложь;
}
}
еще{
пытаться{
фис = новый FileInputStream (имя_файла);
}
catch (FileNotFoundException е) {
fileExists = ложь;
}
}
String serverLine="Сервер: простой веб-сервер Java";
Строка statusLine = null;
Строка contentTypeLine = null;
СтрокаentityBody=null;
Строка contentLengthLine="ошибка";
если (fileExists&&this.fileType){
statusLine="HTTP/1.0 200 ОК"+CRLF;
contentTypeLine="Content-type:"+this.contentType(fileName)+CRLF;
contentLengthLine="Content-Length:"+(new Integer(fis.available())).toString()+CRLF;
}
еще{
if(fileExists&&this.fileType==false){
statusLine="HTTP/1.0 400 BadRequest"+CRLF;
contentTypeLine="текст/html";
entityBody="<HTML>400 Not BadRequest</TITLE></HEAD>"+
"<BODY>400 BadRequest"+
"<br>использование:http://yourHostName:port/"+
"имя_файла.html</BODY></HTML>";
}
иначе, если(fileExists==false){
statusLine="HTTP/1.0 404 Не найден"+CRLF;
contentTypeLine="текст/html";
entityBody="<HTML>404 не найден</TITLE></HEAD>"+
«<BODY>404 не найден»+
"<br>использование:http://yourHostName:port/"+
"имя_файла.html</BODY></HTML>";
}
}
output.write(statusLine.getBytes());
output.write(serverLine.getBytes());
output.write(contentTypeLine.getBytes());
output.write(contentLengthLine.getBytes());
вывод.write(CRLF.getBytes());
если (fileExists&&this.fileType){
sendBytes (физ, вывод);
фис.закрыть();
}
еще{
output.write(entityBody.getBytes());
}
}
}
пытаться{
вывод.закрыть();
бр.закрыть();
сокет.закрыть();
}
улов (Исключение е) {}
}
//Отправляем запрошенную клиентом страницу
Private static void sendBytes(FileInputStream fis,OutputStream os) выдает исключение {
байт [] буфер = новый байт [1024];
целое число байт = 0;
while((bytes=fis.read(буфер))!=-1){
os.write(буфер,0,байт);
}
}
//Устанавливаем содержимое contentType
частная статическая строка contentType (String fileName) {
if(fileName.endsWith(".htm")||fileName.endsWith(".html")){
вернуть «текст/html»;
}
вернуть «имя файла»;
}