Как создать http сервер
Перейти к содержимому

Как создать http сервер

  • автор:

HTTP сервер за 15 минут

За минимальное время написать HTTP сервер, который после запуска сможет корректно ответить браузеру и отдать простую HTML страничку (минимальное время, чтобы кода было мало, чтобы новичку вникать было проще).
У меня это заняло около 15 минут. Сервер вроде справляется с поставленной задачей.

Суть примера — показать что такое Socket, ServerSocket, InputStream, OutputStream, и Thread.

Решение
import java.net.ServerSocket; import java.net.Socket; import java.io.InputStream; import java.io.OutputStream; import java.io.InputStreamReader; import java.io.BufferedReader; /** * Created by yar 09.09.2009 */ public class HttpServer < public static void main(String[] args) throws Throwable < ServerSocket ss = new ServerSocket(8080); while (true) < Socket s = ss.accept(); System.err.println("Client accepted"); new Thread(new SocketProcessor(s)).start(); >> private static class SocketProcessor implements Runnable < private Socket s; private InputStream is; private OutputStream os; private SocketProcessor(Socket s) throws Throwable < this.s = s; this.is = s.getInputStream(); this.os = s.getOutputStream(); >public void run() < try < readInputHeaders(); writeResponse("

Hello from Habrahabr

"); > catch (Throwable t) < /*do nothing*/ >finally < try < s.close(); >catch (Throwable t) < /*do nothing*/ >> System.err.println("Client processing finished"); > private void writeResponse(String s) throws Throwable < String response = "HTTP/1.1 200 OK\r\n" + "Server: YarServer/2009-09-09\r\n" + "Content-Type: text/html\r\n" + "Content-Length: " + s.length() + "\r\n" + "Connection: close\r\n\r\n"; String result = response + s; os.write(result.getBytes()); os.flush(); >private void readInputHeaders() throws Throwable < BufferedReader br = new BufferedReader(new InputStreamReader(is)); while(true) < String s = br.readLine(); if(s == null || s.trim().length() == 0) < break; >> > > >

Сервер

Для работы с сервером и протоколом http в Node.js используется модуль http.

Чтобы создать сервер, следует вызвать метод http.createServer() :

const http = require("http"); const server = http.createServer();

Метод createServer() возвращает объект http.Server . Для обработки подключений в метод createServer передается функция-обработчик:

const http = require("http"); const server = http.createServer(function(request, response)< response.end("Hello METANIT.COM!"); >);

Эта функция принимает два параметра:

  • request : хранит информацию о запросе
  • response : управляет отправкой ответа

В примере выше с помощью метода response.end() в ответ клиенту посылается строка «Hello METANIT.COM!».

Но чтобы сервер мог прослушивать и обрабатывать входящие подключения, у объекта сервера необходимо вызвать метод listen() . Данный метод может принимать различный набор параметров. Но обычно в качестве первого параметра передается номер порта, по которому запускается сервер.

const http = require("http"); const server = http.createServer(function(request, response)< response.end("Hello METANIT.COM!"); >); server.listen(3000);

В данном случае сервер запускается по адресу 3000. Также дополнительно можно передать в метод listen функцию, которая будет срабатывать при запуске сервера:

const http = require("http"); const server = http.createServer(function(request, response)< response.end("Hello METANIT.COM!"); >); server.listen(3000, function()< console.log("Сервер запущен по адресу http://localhost:3000")>);

Например, запустим приложение, и после успешного запуска мы увидим на консоли соответствующее сообщение:

c:\app> node app.js Сервер запущен по адресу http://localhost:3000

Поскольку сервер запущен на порту 3000, то мы можем обратиться к нашему приложению в браузере по адресу http://localhost: 3000

Создание сервера на Node.js

Request

Параметр request позволяет получить информацию о запросе и представляет объект http.IncomingMessage . Отметим некоторые основные свойства этого объекта:

  • headers : возвращает заголовки запроса
  • method : тип запроса (GET, POST, DELETE, PUT)
  • url : представляет запрошенный адрес

Например, определим следующий файл app.js:

const http = require("http"); http.createServer(function(request, response)< console.log("Url:", request.url); console.log("Тип запроса:", request.method); console.log("User-Agent:", request.headers["user-agent"]); console.log("Все заголовки"); console.log(request.headers); response.end(); >).listen(3000, function()< console.log("Сервер запущен по адресу http://localhost:3000")>);

Запустим его и обратимся в браузере по адресу http://localhost:3000/ , и консоль выведет нам информацию о запросе:

c:\app> Сервер запущен по адресу http://localhost:3000 Url: / Тип запроса: GET User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Все заголовки < host: 'localhost:3000', connection: 'keep-alive', 'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"macOS"', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', 'sec-purpose': 'prefetch;prerender', purpose: 'prefetch', accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'sec-fetch-site': 'none', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1', 'sec-fetch-dest': 'document', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,fr;q=0.6,de;q=0.5,tr;q=0.4,zh-CN;q=0.3,zh;q=0.2,bg;q=0.1' >

Response

Параметр response управляет отправкой ответа и представляет объект http.ServerResponse . Среди его функциональности можно выделить следующие методы:

  • statusCode : устанавливает статусный код ответа
  • statusMessage : устанавливает сообщение, отправляемое вместе со статусным кодом
  • setHeader(name, value) : добавляет в ответ один заголовок
  • write : пишет в поток ответа некоторое содержимое
  • writeHead : добавляет в ответ статусный код и набор заголовков
  • end : сигнализирует серверу, что заголовки и тело ответа установлены, в итоге ответ отсылается клиента. Данный метод должен вызываться в каждом запросе.

В общем случае для отправки ответа достаточно вызвать метод end() , в который передаются отправляемые данные:

response.end("Hello METANIT.COM!");

С помощью метода write() можно кусками добавить данные в ответ. Например, изменим файл app.js следующим образом:

const http = require("http"); http.createServer(function(request, response)< response.write("Text 1\n"); response.write("Text 2\n"); response.end("End"); >).listen(3000, function()< console.log("Сервер запущен по адресу http://localhost:3000")>);

Запустим файл и обратимся в браузере к приложению:

Отправка ответа в Node.js

Можно через end() ничего не добавлять в ответ, но в любом случае этот метод следует вызывать при отправке ответа:

const http = require("http"); http.createServer(function(_, response)< response.write("Text 1\n"); response.write("Text 2\n"); response.end(); >).listen(3000, function()< console.log("Сервер запущен по адресу http://localhost:3000")>);
Отправка заголовков

Метод setHeader() позволяет установить заголовки ответа:

const http = require("http"); http.createServer(function(_, response)< response.setHeader("UserId", 12); // установка кастомного заголовка response.setHeader("Content-Type", "text/html; charset=utf-8;"); response.write("

Привет мир

"); response.end(); >).listen(3000, function()< console.log("Сервер запущен по адресу http://localhost:3000")>);

В данном случае для теста устанавливаем кастомный заголовок «UserId», пусть он равен 12. А чтобы отправляемый ответ интерпретировался браузером как код html, для заголовка «Content-Type» устанавливаем значение «text/html; charset=utf-8;». Результат работы:

Отправка заголовков в Node.js

Маршрутизация

По умолчанию Node.js не имеет встроенной системы маршрутизации. Обычно она реализуется с помощью специальных фреймворков типа Express, о котором речь пойдет в следующей главе. Однако если необходимо разграничить простейшую обработку пары-тройки маршрутов, то вполне можно использовать для этого свойство url объекта Request. Например:

const http = require("http"); http.createServer(function(request, response)< response.setHeader("Content-Type", "text/html; charset=utf-8;"); if(request.url === "/home" || request.url === "/")< response.write("

Home

"); > else if(request.url == "/about")< response.write("

About

"); > else if(request.url == "/contact")< response.write("

Contacts

"); > else< response.write("

Not found

"); > response.end(); >).listen(3000);

В данном случае обрабатываются три маршрута. Если идет обрашение к корню сайта или по адресу localhost:3000/home , то пользователю выводится строка «Home». Ели обращение идет по адресу localhost:3000/about , то пользователю в браузере отображается строка About и так далее. Если запрошенный адрес не соответствует ни одному маршруту, то выводится заговлок «Not Found».

Маршрутизация в Node.js

Однако опять же отмечу, что рамках специальных фреймворков, которые работают поверх Node.js, например, Express, есть более удобные способы для обработки маршрутов, которые нередко и используются.

Переадресация

Переадресация предполагает отправку статусного кода 301 (постоянная переадресация) или 302 (временная переадресация) и заголовка Location , который указывает на новый адрес. Например, выполним переадресацию с адреса localhost:3000/ на адрес localhost:3000/newpage

const http = require("http"); http.createServer(function(request, response) < response.setHeader("Content-Type", "text/html; charset=utf-8;"); if(request.url === "/")< response.statusCode = 302; // временная переадресация // на адрес localhost:3000/newpage response.setHeader("Location", "/newpage"); >else if(request.url == "/newpage") < response.write("New address"); >else < response.statusCode = 404; // адрес не найден response.write("Not Found"); >response.end(); >).listen(3000);

Как настроить локальный сервер для тестирования?

Эта статья объясняет как установить простой локальный тестовый сервер на вашем компьютере, а так же основы его использования.

Требования: Сначала вам необходимо изучить как работает интернет, а также что такое веб-сервер (en-US) .
Цель: Вы научитесь как устанавливать локальный тестовый сервер.

Локальные и удалённые файлы

На протяжении всего обучения, вы будете открывать примеры непосредственно в браузере — двойным кликом по HTML файлу, перетаскиванием файла в окно браузера, или через меню File > Open. и указывая необходимый HTML файл. Существует множество способов как это сделать.

Если веб-адрес начинается с file:// в котором далее прописан путь к файлу на вашем локальном жёстком диске, значит используется локальный файл. В противоположность этому, если вы откроете на просмотр один из наших примеров, расположенных на GitHub (или пример расположенный на любом другом удалённом сервере), веб-адрес будет начинаться с http:// или https:// , что означает что файл был получен через HTTP.

Проблемы тестирования локальных файлов

Некоторые примеры могут не запуститься, если вы попробуете открыть их как локальные файлы. Это может произойти по нескольким причинам, самые распространённые из которых:

  • Они содержат асинхронные запросы. Некоторые браузеры (включая Chrome) не будут запускать асинхронные запросы (см. Fetching data from the server), если вы просто запускаете пример из локального файла. Это связано с ограничениями безопасности (для получения дополнительной информации о безопасности в Интернете, ознакомьтесь с Website security).
  • Они имеют серверный язык. Серверные языки (например, PHP или Python) требуют специального сервера для интерпретации кода и предоставления результатов.

Запуск простого локального HTTP сервера

Чтобы обойти проблему асинхронных запросов, нам нужно протестировать такие примеры, запустив их через локальный веб-сервер. Один из самых простых способов сделать это для наших целей — использовать модуль SimpleHTTPServer Python.

Для этого нужно:

  1. Установить Python. Если вы пользуетесь Linux или Mac OS X, всё уже готово в вашей системе. Если вы пользователь Windows, вы можете скачать установочный файл с домашней страницы Python:
    • Зайдите на python.org
    • В секции загрузок, выберите линк для Python «3.xxx».
    • Внизу страницы выберите Windows x86 executable installer и скачайте его.
    • После загрузки файла запустите его.
    • На первой странице инсталлятора выберите чекбокс «Add Python 3.xxx to PATH».
    • Нажмите Install, затем нажмите Close когда установка закончится.
  2. Откройте командную строку (Windows)/ (OS X/Linux). Для проверки установки Python введите следующую команду:

# include the directory name to enter it, for example cd Desktop # use two dots to jump up one directory level if you need to cd .. 
# If Python version returned above is 3.X python -m http.server # If Python version returned above is 2.X python -m SimpleHTTPServer 

Примечание: . Если у вас уже есть что-то на порту 8000, вы можете выбрать другой порт, запустив команду сервера, за которой следует альтернативный номер порта, например: python -m http.server 7800 (Python 3.x) или python -m SimpleHTTPServer 7800 (Python 2.x). Затем вы можете получить доступ к своему контенту на localhost: 7800 .

Запуск серверных языков локально

Модуль Python SimpleHTTPServer (python 2.0) http.server (python 3.0) полезен, но он не знает, как запускать код, написанный на таких языках, как Python, PHP или JavaScript. Чтобы справиться с этим, вам понадобится нечто большее — именно то, что вам нужно, зависит от языка сервера, который вы пытаетесь запустить. Вот несколько примеров:

  • Для запуска кода на стороне сервера Python вам необходимо использовать веб-инфраструктуру Python. Вы можете узнать, как использовать структуру Django, прочитав Django Web Framework (Python). Flask также является хорошей (чуть менее тяжёлой) альтернативой Django. Чтобы запустить это, ознакомьтесь с install Python/PIP, а затем установите Flask с помощью pip3 install flask . На этом этапе вы сможете запустить примеры Python Flask, используя, например, python3 python-example.py , затем перейдя на localhost: 5000 в свой браузер.
  • Чтобы запустить серверный код Node.js (JavaScript), вам нужно использовать Node.js или фреймворк, построенный поверх него. Express — хороший выбор — см. Express Web Framework (Node.js/JavaScript).
  • Чтобы запустить PHP-серверный код, вам понадобится настройка сервера, которая может интерпретировать PHP. Хорошими вариантами для локального тестирования PHP являются MAMP (Mac и Windows), AMPPS (Mac, Windows, Linux) и LAMP (Linux, Apache, MySQL и PHP / Python / Perl). Это полные пакеты, которые создают локальные настройки, позволяющие запускать базы данных Apache, PHP и MySQL.

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 3 авг. 2023 г. by MDN contributors.

Простой http сервер.¶

Любой online-сервис начинается с того, что необходимо приложение, которое способно принимать и обрабатывать http-запросы.

В python есть встроенный модуль, который полвзоляет создавать простой http-сервер.

from http.server import BaseHTTPRequestHandler from http.server import HTTPServer def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) try: httpd.serve_forever() except KeyboardInterrupt: httpd.server_close() 

Если запустить функцию run() , то будет запущен http-сервер, и если в браузере Вы введете 127.0.0.1:8000 , то Вам вернутся ответ, но ответ будет содержать ошибку, потому что сервер не знает как обрабатывать запросы.

Для того что бы исправить эту ошибку трубется в обработчике( BaseHTTPRequestHandler ) реализовать метод по обработке GET-запросов:

class HttpGetHandler(BaseHTTPRequestHandler): """Обработчик с реализованным методом do_GET.""" def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(''.encode()) self.wfile.write('Простой HTTP-сервер.'.encode()) self.wfile.write('Был получен GET-запрос.'.encode()) 

Теперь, если запустить сервер с новым обработчиком run(handler_class=HttpGetHandler) , то при переходе по адресу 127.0.0.1:8000 можно будет увидеть ответ на запрос.

Обратите внимание, что при формировании ответа обработчика был использован метод encode() у строк. Сделано этого потому что в теле ответа могут быть использованы только байтовые строки.

Задания¶

  1. Ознакомьтесь с описанием протокола HTTP.
  2. Дополните обработчик запросов таким образом, что бы он мог обрабатывать запросы по методам POST, PUT и HEAD. Для проверки реализации используйте библиотку requests.

© Copyright Revision d00c0df4 .

Built with Sphinx using a theme provided by Read the Docs.
Read the Docs v: latest

Versions latest Downloads html On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *