powered by simpleCommunicator - 2.0.18     © 2024 Programmizd 02
Map
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничный http-echo-time-server на разных языках разработки
25 сообщений из 27, страница 1 из 2
Тяпничный http-echo-time-server на разных языках разработки
    #40117137
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет друзья.

С пятницей всех!

Как реализуется простой http-echo-time-server на разных языках разработки и технологиях. C++, C#, Delphi
Python, Go e.t.c?

Пример пользования:

Код: sql
1.
curl -X GET http://localhost:8080/time



Отвечает

Код: sql
1.
2.
200 OK
{ "time" : "2021-12-03T16:45:33" }


Как-бы вы делали?

Какое количество мозговых усилий разработки и внешних зависимостей нужно затащить в код
чтобы реализовать тестовый ендпоинт для тестирования чего-либо?

Разумеется я предполагаю embedded http server. Тоесть такой сервер который встраивается в ваш код.
Всякие Апачи и IIS - не наш вариант!
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117178
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Это очень сильно зависит от фремйворка, а не от языка.
Вот пример с главной страницы dlang
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
#!/usr/bin/env dub
/+ dub.sdl:
dependency "vibe-d" version="~>0.9.0"
+/
void main()
{
    import vibe.d;
    listenHTTP(":8080", (req, res) {
        res.writeBody("Hello, World: " ~ req.path);
    });
    runApplication();
}



Я делал пример на safe-c - тоже немногим длиннее, http сервер в стандартной библиотеке. Нужно просто написать коллбэки.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117367
Фотография VSVLAD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Реализовывал свой Embedded Http сервер на VB.NET. Использовал TcpListener + TcpClient. Могу пример показать, как сделать аналогично вашего примера (возврат времени). Сервер очень простой, только GET/POST запросы принимает, при чём для POST только в виде сырых данных, GET обрабатывается и возвращается коллекция параметров, чтобы пользователь мог сразу писать бизнес логику.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117381
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VSVLAD,

Давай
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117391
Фотография VSVLAD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Вот пример с временем. В спойлере готовый класс. Для небольших и в меру несложных проектов пойдёт. Я делал консольное приложение и оно поднимало веб-интерфейс, чтобы можно было управлять им с других серверов нашей локальной сети. Со своей задачей справлялось. В приципе если подшаманить, можно даже загрузку файлов реализовать и прочий "взрослый" функционал, но это конечно же не полноценный сервер

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
Option Explicit On
Option Strict On

Imports System.IO
Imports WebData.MicroHTTP

Public Module Program

    Private WithEvents server As New WebServer(88)

    Public Sub Main()
        server.Start()

        Console.WriteLine("Сервер запущен")
        Console.ReadLine()
    End Sub

    Private Sub server_ProcessRequest(sender As Object, e As ProcessRequestEventArgs) Handles server.ProcessRequest
        e.Response.Encoding = Text.Encoding.GetEncoding(1251)

        Select Case e.Request.Url
            Case "/"
                e.Response.WriteHead(HttpCodes.OK, ContentTypes.TEXT_HTML).WriteLine().Write("Привет!")

            Case "/time"
                e.Response.
                WriteHead(HttpCodes.OK, "application/json").
                WriteLine().
                Write($"{{""time"":""{Now.ToString("yyyy-MM-ddTHH:mm:ss")}""}}")

            Case Else
                e.Response.WriteHead(HttpCodes.NOT_FOUND, ContentTypes.TEXT_HTML).WriteLine().Write("Страница не найдена")

        End Select
    End Sub

End Module




Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
Option Explicit On
Option Strict On

Imports System.Threading
Imports System.Net.Sockets
Imports System.Net
Imports System.Text
Imports System.IO
Imports System.Text.RegularExpressions

Namespace MicroHTTP

    ''' <summary>Класс содержит данные события ProcessRequest</summary>
    Public Class ProcessRequestEventArgs
        Inherits EventArgs

        Public ReadOnly Property Request As Request
        Public ReadOnly Property Response As Response

        Sub New(req As Request, res As Response)
            Me.Request = req
            Me.Response = res
        End Sub

    End Class

    ''' <summary>Класс содержит данные события ProcessError</summary>
    Public Class ProcessErrorEventArgs
        Inherits EventArgs

        Public ReadOnly Property Exception As Exception

        Sub New(ex As Exception)
            Me.Exception = ex
        End Sub
    End Class

    ''' <summary>Список кодов ответа</summary>
    Public Enum HttpCodes
        OK = 200
        MOVED_PERMANENTLY = 301
        FOUND = 302
        BAD_REQUEST = 400
        FORBIDDEN = 403
        NOT_FOUND = 404
        METHOD_NOT_ALLOWED = 405
        SERVER_ERROR = 500
        NOT_IMPELEMENTED = 501
        SERVICE_UNAVAILABLE = 503
    End Enum

    ''' <summary>Список предопределенных MIME типов</summary>
    Public Enum ContentTypes
        TEXT_HTML
        TEXT_HTML_UTF8
        TEXT_PLAIN
        TEXT_PLAIN_UTF8
        TEXT_CSS
        TEXT_JAVASCRIPT
        IMAGE_PNG
        IMAGE_JPEG
        IMAGE_GIF
        APP_OCTET_STREAM
    End Enum

    ''' <summary>Класс предоставляет объект для создания асинхронного слушателя порта</summary>
    Public Class WebServer

        Public Event ProcessRequest(ByVal sender As Object, ByVal e As ProcessRequestEventArgs)
        Public Event ProcessError(ByVal sender As Object, ByVal e As ProcessErrorEventArgs)

        Public Property ReadTimeout As Integer = 15000
        Public Property WriteTimeout As Integer = 15000

        Private reContentLength As New Regex("Content-Length:\s+(\d+)", RegexOptions.Compiled Or RegexOptions.IgnoreCase Or RegexOptions.Multiline)
        Private Const HTTP_NEW_LINE = vbCrLf & vbCrLf

        Private listener As TcpListener
        Private listenerThread As Thread

        ''' <summary>Конструктор с параметрами по-умолчанию: на всех интерфейсах и порт 80</summary>
        Public Sub New()
            Me.New(IPAddress.Any, 80)
        End Sub

        ''' <summary>Конструктор с параметрами порта</summary>
        Public Sub New(Port As Integer)
            Me.New(IPAddress.Any, Port)
        End Sub

        ''' <summary>Конструктор с параметрами локального адреса и порта</summary>
        Public Sub New(LocalAddress As IPAddress, Port As Integer)
            listener = New TcpListener(LocalAddress, Port)
            listenerThread = New Thread(New ThreadStart(AddressOf ProcessListener))
        End Sub

        ''' <summary>Запуск сервера</summary>
        Public Sub Start()
            listener.Start()
            listenerThread.Start()
        End Sub

        ''' <summary>Остановка сервера</summary>
        Public Sub Finish()
            listener.Stop()
            listenerThread.Abort()
        End Sub

        Private Sub ProcessListener()
            Dim threadCount, portsCount As Integer

            ThreadPool.GetMinThreads(threadCount, portsCount)
            ThreadPool.SetMaxThreads(threadCount, portsCount)

            Do While True
                ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ProcessWorkItem), listener.AcceptTcpClient())
            Loop
        End Sub

        Private Sub ProcessWorkItem(State As Object)
            Dim remoteTcpClient As TcpClient = Nothing, remoteStream As NetworkStream = Nothing

            Try
                'Подключаемся
                remoteTcpClient = DirectCast(State, TcpClient)
                remoteTcpClient.ReceiveTimeout = Me.ReadTimeout
                remoteTcpClient.SendTimeout = Me.WriteTimeout

                'Читаем запрос от клиента
                remoteStream = remoteTcpClient.GetStream()
                Dim dataRead(8192) As Byte, bytesRead As Integer
                Dim builder As New StringBuilder()

                Do
                    bytesRead = remoteStream.Read(dataRead, 0, dataRead.Length)
                    builder.Append(Encoding.UTF8.GetString(dataRead, 0, bytesRead))
                Loop While Not IsValidHttpPacketLength(builder)

                'Препроцессинг
                Dim reqClass As New Request(builder.ToString(), remoteTcpClient)
                Dim resClass As New Response()

                'Обрабатываем в приложении
                RaiseEvent ProcessRequest(remoteTcpClient, New ProcessRequestEventArgs(reqClass, resClass))

                'Отвечаем на запрос
                Dim dataWrite = resClass.Encoding.GetBytes(resClass.Content)
                remoteStream.Write(dataWrite, 0, dataWrite.Length)

            Catch ex As Exception
                RaiseEvent ProcessError(remoteTcpClient, New ProcessErrorEventArgs(ex))

            Finally 'Закрываемся
                If remoteStream IsNot Nothing Then remoteStream.Close()
                If remoteTcpClient IsNot Nothing Then remoteTcpClient.Close()

            End Try
        End Sub

        ''' <summary>
        ''' Определяет получили ли мы полностью HTTP пакет или ещё нет
        ''' </summary>
        ''' <param name="BufferBuilder">Накопительный пакет с StringBuilder</param>
        Private Function IsValidHttpPacketLength(BufferBuilder As StringBuilder) As Boolean
            Dim strBuffer = BufferBuilder.ToString()
            Dim posCrLf = strBuffer.IndexOf(HTTP_NEW_LINE)

            If strBuffer(0) = "G"c Then
                Return posCrLf > -1

            ElseIf strBuffer(0) = "P"c Then
                If posCrLf > -1 Then
                    Dim posContentLength = strBuffer.IndexOf("Content-Length", 0, posCrLf)

                    If posContentLength > -1 Then
                        Dim realPacketLength = CInt(strBuffer.Length - (posCrLf + 2))
                        Dim headerPacketLength = CInt(reContentLength.Match(strBuffer).Groups(1).Value)

                        If realPacketLength < headerPacketLength Then
                            Return False
                        Else
                            Return True
                        End If
                    End If

                    Return True
                Else
                    Return False
                End If
            Else
                Return True
            End If
        End Function

    End Class

    ''' <summary>Класс предоставляет интерфейс для входящих запросов от клиентов</summary>
    Public Class Request

        Public ReadOnly Property RequestRaw As String
        Public ReadOnly Property RemoteIP As String

        Public ReadOnly Property Method As String
        Public ReadOnly Property Host As String
        Public ReadOnly Property Headers As Dictionary(Of String, String)
        Public ReadOnly Property UserAgent As String
        Public ReadOnly Property Cookie As String

        Public ReadOnly Property OriginalUrl As String
        Public ReadOnly Property Url As String
        Public ReadOnly Property UrlParameters As Dictionary(Of String, String)
        Public ReadOnly Property PostData As String

        Private Const HTTP_NEW_LINE = vbCrLf & vbCrLf

        'Парсим пакет
        Public Sub New(ByVal HttpPacket As String, HttpTcpClient As TcpClient)
            Dim idxHeadersEnd = HttpPacket.IndexOf(HTTP_NEW_LINE)
            If idxHeadersEnd = -1 Then Throw New Exception("MicroHTTP.ParseHeaderLine() :: Не найден правильный HTTP заголовок:" & vbCrLf & HttpPacket)

            Dim headerNumber = 0
            Dim strHeaders = HttpPacket.Substring(0, idxHeadersEnd)
            Me.PostData = HttpPacket.Substring(idxHeadersEnd + 4)

            Me.RemoteIP = DirectCast(HttpTcpClient.Client.RemoteEndPoint, IPEndPoint).Address.ToString()
            Me.RequestRaw = strHeaders
            Me.Headers = New Dictionary(Of String, String)
            Me.UrlParameters = New Dictionary(Of String, String)

            For Each xLine In strHeaders.Split(New String() {vbCrLf}, StringSplitOptions.None)
                If headerNumber = 0 Then 'Для первого заголовка с GET/POST

                    'Метод HTTP
                    Dim strFirstHeader() = Split(xLine, " "c)
                    Dim strQuery As String = String.Empty

                    Me.Method = strFirstHeader(0)
                    Me.OriginalUrl = strFirstHeader(1)

                    'Отделяем URL и GET параметры
                    Dim idxQueryStart = Me.OriginalUrl.IndexOf("?"c)

                    If idxQueryStart >= 0 Then
                        Me.Url = Me.OriginalUrl.Substring(0, idxQueryStart)
                        strQuery = Me.OriginalUrl.Substring(idxQueryStart + 1)
                    Else
                        Me.Url = Me.OriginalUrl
                    End If

                    'Добавляем параметры в коллекцию
                    Select Case Me.Method
                        Case "GET", "HEAD", "DELETE", "PUT"
                            If Not String.IsNullOrEmpty(strQuery) Then Me.UrlParameters = New UrlParameters(strQuery, True)

                        Case "POST"
                            ' Не готово [application/x-www-form-urlencoded + multipart/form + RAW]

                    End Select

                Else

                    'Для специальных заголовков
                    Dim kvp = ParseHeaderLine(xLine)

                    Select Case kvp.Key.ToLowerInvariant()
                        Case "host"
                            Me.Host = kvp.Value

                        Case "user-agent"
                            Me.UserAgent = kvp.Value

                        Case "cookie"
                            Me.Cookie = kvp.Value

                    End Select

                    'Для всех заголовков
                    Me.Headers.Add(kvp.Key, kvp.Value)
                End If

                headerNumber = +1
            Next
        End Sub

        ''' <summary>Внутренний метод для разделения строки на ключ и значение</summary>
        Private Shared Function ParseHeaderLine(TextLine As String) As KeyValuePair(Of String, String)
            TextLine = TextLine.TrimStart()

            Dim idxEqual = TextLine.IndexOf(":"c)
            If idxEqual = -1 Then Throw New Exception("MicroHTTP.ParseHeaderLine() > Получен неверный заголовок:" & vbCrLf & TextLine)

            Dim strKey = TextLine.Substring(0, idxEqual).TrimEnd()
            Dim strValue = TextLine.Substring(idxEqual + 1).TrimStart()

            Return New KeyValuePair(Of String, String)(strKey, strValue)
        End Function

    End Class

    ''' <summary>Класс предоставляет интерфейс для взаимодействия с клиентом и отправки ответов</summary>
    Public Class Response

        Private Shared ContentTypesList As New Dictionary(Of ContentTypes, String) From {
        {ContentTypes.TEXT_HTML, "text/html"},
        {ContentTypes.TEXT_HTML_UTF8, "text/html; charset=utf-8"},
        {ContentTypes.TEXT_PLAIN, "text/plain"},
        {ContentTypes.TEXT_PLAIN_UTF8, "text/plain; charset=utf-8"},
        {ContentTypes.TEXT_CSS, "text/css"},
        {ContentTypes.TEXT_JAVASCRIPT, "application/x-javascript"},
        {ContentTypes.IMAGE_PNG, "image/png"},
        {ContentTypes.IMAGE_JPEG, "image/jpeg"},
        {ContentTypes.IMAGE_GIF, "image/gif"},
        {ContentTypes.APP_OCTET_STREAM, "application/octet-stream"}
        }

        Private Shared HttpCodesList As New Dictionary(Of HttpCodes, String) From {
        {HttpCodes.OK, "OK"},
        {HttpCodes.MOVED_PERMANENTLY, "Moved Permanently"},
        {HttpCodes.FOUND, "Found"},
        {HttpCodes.BAD_REQUEST, "Bad Request"},
        {HttpCodes.FORBIDDEN, "Forbidden"},
        {HttpCodes.NOT_FOUND, "Not Found"},
        {HttpCodes.METHOD_NOT_ALLOWED, "Method Not Allowed"},
        {HttpCodes.SERVER_ERROR, "Server Error"},
        {HttpCodes.NOT_IMPELEMENTED, "Not Impelemented"},
        {HttpCodes.SERVICE_UNAVAILABLE, "Service Unavailable"}
        }

        Private sb As New StringBuilder

        ''' <summary>Свойство предоставляет доступ к ответу для клиента</summary>
        Public ReadOnly Property Content As String
            Get
                Return sb.ToString()
            End Get
        End Property

        ''' <summary>Свойство предоставляет возможность предопределить кодировку ответа.
        ''' Бинарные данные должны пересылаться в однобайтовой кодировке ASCII, а некоторые текстовые данные могут быть в UTF-8 или Unicode или ANSI
        ''' </summary>
        Public Property Encoding As Encoding = Encoding.UTF8

        ''' <summary>Очищает буфер ответа</summary>
        Public Function Clear() As Response
            sb.Clear()
            Return Me
        End Function

        ''' <summary>Добавляет значение в буфер ответа</summary>
        Public Function Write(ByVal Value As String) As Response
            sb.Append(Value)
            Return Me
        End Function

        Public Function Write(ByVal Value() As Byte) As Response
            sb.Append(Encoding.GetString(Value))
            Return Me
        End Function

        Public Function WriteFormat(ByVal FormatString As String, ParamArray Values() As Object) As Response
            sb.AppendFormat(FormatString, Values)
            Return Me
        End Function

        Public Function WriteLine(ByVal Value As String) As Response
            sb.AppendLine(Value)
            Return Me
        End Function

        Public Function WriteLine() As Response
            sb.AppendLine()
            Return Me
        End Function

        ''' <summary>Добавляет основные заголовки без заключительного переноса строки</summary>
        Public Function WriteHead(Code As HttpCodes, ContentType As ContentTypes) As Response
            sb.AppendFormat("HTTP/1.0 {0} {1}", CInt(Code), HttpCodesList(Code)).AppendLine()
            sb.AppendFormat("X-Powered-By: MicroHTTP").AppendLine()
            sb.AppendFormat("Content-Type: {0}", ContentTypesList(ContentType)).AppendLine()
            Return Me
        End Function

        ''' <summary>Добавляет основные заголовки без заключительного переноса строки</summary>
        Public Function WriteHead(Code As HttpCodes, ContentType As String) As Response
            sb.AppendFormat("HTTP/1.0 {0} {1}", CInt(Code), HttpCodesList(Code)).AppendLine()
            sb.AppendFormat("X-Powered-By: MicroHTTP").AppendLine()
            sb.AppendFormat("Content-Type: {0}", ContentType).AppendLine()
            Return Me
        End Function

        ''' <summary>Добавляет основные заголовки без заключительного переноса строки</summary>
        Public Function WriteHead(Code As Short, Description As String, ContentType As String) As Response
            sb.AppendFormat("HTTP/1.0 {0} {1}", CInt(Code), Description).AppendLine()
            sb.AppendFormat("X-Powered-By: MicroHTTP").AppendLine()
            sb.AppendFormat("Content-Type: {0}", ContentType).AppendLine()
            Return Me
        End Function

        ''' <summary>Метод возвращает контент тип на основе расширения файла</summary>
        Public Function ByFileExtension(ByVal strFileExtension As String) As ContentTypes
            Select Case strFileExtension.Replace(".", "").ToLowerInvariant()
                Case "jpg", "jpeg", "jpe"
                    Return ContentTypes.IMAGE_JPEG
                Case "gif"
                    Return ContentTypes.IMAGE_GIF
                Case "png"
                    Return ContentTypes.IMAGE_PNG
                Case "htm", "html"
                    Return ContentTypes.TEXT_HTML
                Case "txt", "csv"
                    Return ContentTypes.TEXT_PLAIN
                Case "js"
                    Return ContentTypes.TEXT_JAVASCRIPT
                Case "css"
                    Return ContentTypes.TEXT_CSS
                Case Else
                    Return ContentTypes.APP_OCTET_STREAM
            End Select
        End Function

        ''' <summary>Предопределенный метод для обработки запросов к статичным файлам</summary>
        Public Sub ProcessAsStaticFile(RootWebPath As String, RequestUrl As String)
            If Directory.Exists(RootWebPath) Then
                Dim filePath As String = Path.Combine(RootWebPath, RequestUrl.Replace("/", "\").Substring(1))

                If File.Exists(filePath) Then
                    Dim fi As FileInfo = New FileInfo(filePath)

                    Select Case Me.ByFileExtension(fi.Extension)
                        Case ContentTypes.TEXT_CSS, ContentTypes.TEXT_JAVASCRIPT, ContentTypes.TEXT_HTML, ContentTypes.TEXT_PLAIN
                            Me.Encoding = Text.Encoding.UTF8
                            Me.WriteHead(HttpCodes.OK, Me.ByFileExtension(fi.Extension)).WriteLine().
                            Write(File.ReadAllText(filePath, Text.Encoding.UTF8))

                        Case Else
                            Me.Encoding = Text.Encoding.GetEncoding(1251)
                            Me.WriteHead(HttpCodes.OK, Me.ByFileExtension(fi.Extension)).WriteLine().
                            Write(File.ReadAllText(filePath, Text.Encoding.GetEncoding(1251)))

                    End Select

                Else
                    Me.Encoding = Text.Encoding.UTF8
                    Me.WriteHead(HttpCodes.NOT_FOUND, "Content-type: text/html; charset=utf-8").WriteLine().
                    Write("<h1>Страница не найдена!</h1>")

                End If
            End If
        End Sub

        ''' <summary>Предопределенный метод для переадресации на другой Url</summary>
        Public Sub ProcessAsRedirect(UrlDestination As String)
            Me.WriteHead(HttpCodes.MOVED_PERMANENTLY, ContentTypes.TEXT_HTML).
            WriteFormat("Location: {0}", UrlDestination).WriteLine()
        End Sub

    End Class

    ''' <summary>Provides somewhat lenient URL encoding suited for Unicode Uris.</summary>
    Public Class UrlEncoding

        Shared ReadOnly urlEncStrings() As String = InitUrlStrings()

        Private Sub New()
        End Sub

        Private Shared Function InitUrlStrings() As String()
            Dim urlEncStrings As String() = New String(255) {}
            For i As Integer = 0 To 254
                urlEncStrings(i) = "%" & i.ToString("X2")
            Next
            Return urlEncStrings
        End Function

        ''' <summary>
        ''' Url encodes a string, but allow unicode characters to pass unencoded.
        ''' </summary>
        ''' <param name="value">The string to encode.</param>
        ''' <returns>The Url encoded string.</returns>
        Public Shared Function Encode(value As String) As String
            If value Is Nothing Then
                Return Nothing
            End If

            Dim ret As New StringBuilder(value.Length)

            For i As Integer = 0 To value.Length - 1
                Dim ch As Char = value(i)
                If ch = " "c Then
                    ret.Append("+"c)
                ElseIf Not IsSafe(ch) Then
                    ret.Append(urlEncStrings(AscW(ch)))
                Else
                    ret.Append(ch)
                End If
            Next

            Return ret.ToString()
        End Function

        ''' <summary>
        ''' Decodes a Url using System.Uri's Unescape method.
        ''' </summary>
        ''' <param name="value">The string to decode.</param>
        ''' <returns>The Url decoded string.</returns>
        Public Shared Function Decode(value As String) As String
            If value Is Nothing Then
                Return Nothing
            End If

            Return Uri.UnescapeDataString(value.Replace("+", "%20"))
        End Function

        Private Shared Function IsSafe(ch As Char) As Boolean
            If Char.IsLetterOrDigit(ch) Then
                Return True
            End If

            Select Case ch
                Case "'"c, "("c, ")"c, "["c, "]"c, "*"c, "-"c, "."c, "!"c, "_"c
                    Return True
            End Select

            If AscW(ch) > 255 Then Return True
            Return False
        End Function

    End Class

    ''' <summary>
    ''' Represents a URI query parsed in name/value pairs.
    ''' </summary>
    Public Class UrlParameters
        Inherits Dictionary(Of String, String)

        ''' <summary>
        ''' Parse a query from a given Uri.
        ''' </summary>
        ''' <param name="uri">The URI to parse from</param>
        Public Sub New(uri As Uri)
            Me.New(uri.Query.TrimStart("?"c), True)
        End Sub

        ''' <summary>
        ''' Parse a query from a URL encoded query string.
        ''' </summary>
        ''' <param name="query">The query string to parse from.</param>
        Public Sub New(query As String)
            Me.New(query, True)
        End Sub

        ''' <summary>
        ''' Parse a query from a given string.
        ''' </summary>
        ''' <param name="Query">The query string to parse from.</param>
        ''' <param name="UrlEncoded">A value indicating whether the string is URL encoded or not.</param>
        Public Sub New(Query As String, UrlEncoded As Boolean)
            For i As Integer = 0 To Query.Length - 1
                Dim start As Integer = i
                Dim equalIndex As Integer = -1
                While i < Query.Length
                    If Query(i) = "="c Then
                        If equalIndex < 0 Then
                            equalIndex = i
                        End If
                    ElseIf Query(i) = "&"c Then
                        Exit While
                    End If
                    i += 1
                End While

                Dim name As String
                Dim value As String

                If equalIndex < 0 Then
                    name = Query.Substring(start, i - start)
                    value = String.Empty
                Else
                    name = Query.Substring(start, equalIndex - start)
                    value = Query.Substring(equalIndex + 1, (i - equalIndex) - 1)
                End If

                If UrlEncoded Then
                    Me.Add(UrlEncoding.Decode(name), UrlEncoding.Decode(value))
                Else
                    Me.Add(name, value)
                End If

                If i = Query.Length - 1 AndAlso Query(i) = "&"c Then
                    Me.Add(Nothing, String.Empty)
                End If
            Next
        End Sub

    End Class

End Namespace


...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117403
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нифига себе букв. Там всё надо?
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117404
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот еще Node.

Код: javascript
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
const http = require("http");

const requestListener = function (req, res) {
    if (req.url == '/time') {
      res.setHeader("Content-Type", "application/json");
      res.writeHead(200);
      let datetime = new Date();
      res.end(`{"time": "` + datetime.toISOString() + `"}`);
    }
};

const server = http.createServer(requestListener);

server.listen(8080, 'localhost', () => {
    console.log(`Server is running`);
});
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117407
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Java с использованием Jetty 11.0.7
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
    private static class TimeServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setStatus(200);
            resp.setHeader("Content-Type", "application/json");
            resp.getWriter().print("{ \"time\" : \"" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "\"}");
        }
    }

    public TimeServer(String[] args) throws Exception {
        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        int port    = 8080;
        String host = "127.0.0.1";
        connector.setPort(port);
        connector.setHost(host);
        connector.setName("Connector-1");
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        context.addServlet(new ServletHolder(new TimeServlet()), "/time");

        server.start();
        server.join();
    }

    public static void main(String[] args) throws Exception {
        new TimeServer(args);
    }


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jetty.server.version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jetty.server.version}</version>
        </dependency>



Удобно для всяких там http-mocks. Размер бинарника получается 2 мегабайта. Стартует 2-3 секунды.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117408
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Завтра соберу эхо-сервер для Spring WebFlux. Надо взять только один из рабочих проектов и выкинуть всё ненужное.
Реактивность для эхо-сервера (для данного топика!) не нужна. Хотя любопытно посмотреть что покажет JMeter если сравнивать например
Node и WebFlux.

И DLang-овский тоже сравнить.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117417
ShSerge
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Нода мне больше нравится.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117418
ShSerge
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня на ней очень офигенный проект висит. Висит не потому что я - дурак, или кто-то дурак, а потому что сложный.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117428
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
При чем тут дурак или не дурак?

Нода - лёгкая. Очень быстро стартует.
У меня вообще-то к ней нет претензий.
Единственная претензия - это язык разработки где слабая типизация.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117434
Фотография VSVLAD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Вот пример, где меньше букв :) но это уже на основе встроенного класса HttpListener. Как уже сказали, всё зависит от библиотек/фреймворков, которые идут к языку. Мне лично HttpListener не нравится по определенным причинам. Поэтому реализовал свой сервер на сокетах

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
Option Explicit On
Option Strict On

Imports System.IO
Imports System.Net

Public Module Program

    Private WithEvents server As New HttpListener()

    Public Sub Main()
        server.Prefixes.Add("http://*:88/")
        server.Start()

        Do While True
            Dim context = server.GetContext()

            Select Case context.Request.Url.AbsolutePath
                Case "/time"
                    context.Response.StatusCode = 200

                    Using str As New StreamWriter(context.Response.OutputStream)
                        str.WriteAsync($"{{""time"":""{Now.ToString("yyyy-MM-ddTHH:mm:ss")}""}}")
                    End Using

                Case Else
                    context.Response.StatusCode = 404

                    Using str As New StreamWriter(context.Response.OutputStream)
                        str.WriteAsync("Not Found")
                    End Using

            End Select
        Loop
    End Sub

End Module
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117439
Go (где SRC под Go ?!)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
package main

import (
    "fmt"
    "net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "hello\n")
}

func headers(w http.ResponseWriter, req *http.Request) {
    for name, headers := range req.Header {
        for _, h := range headers {
            fmt.Fprintf(w, "%v: %v\n", name, h)
        }
    }
}

func main() {
    http.HandleFunc("/hello", hello)
    http.HandleFunc("/headers", headers)

    http.ListenAndServe(":8090", nil)
}
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117440
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да. Это копи-паста из стандартной документации по Go-хомяку.

Я тоже ее вчера взял и начал делать функцию текущего даты-времени. Но уже было поздно и думал сегодня сделаю.

Почему эта документация выглядит как-то по уродски? Язык - хороший.
Но пишут как для детей. Будто - это язык для обучения информатике в детском садике? Никто не знает?
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117441
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
VSVLAD, о спс. Вот это уже получше выглядит.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117451
mayton
Почему эта документация выглядит как-то по уродски? Язык - хороший.
Но пишут как для детей. Будто - это язык для обучения информатике в детском садике? Никто не знает?

потому что гугл его придумал, чтобы программисты могли максимально быстро втянуться в процесс
он задуман, как универсальный язык для всего парка программеров
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117528
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сделал на Гошке.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
package main

import (
    "fmt"
    "time"
    "net/http"
)

func timeHandler(w http.ResponseWriter, req *http.Request) {
    currentTime := time.Now()
    fmt.Fprintln(w, "{ \"time\" : \"", currentTime, "\" } ")    
}

func main() {
    fmt.Println("Starting...")
    http.HandleFunc("/time", timeHandler)
    http.ListenAndServe("localhost:8080", nil)
}



Форматирование даты выглядит как-то стрёмно... ну да бох с ним. Знающие - пофиксят а мне и так хорошо.
Код: sql
1.
{ "time" : " 2021-12-05 18:40:00.957201172 +0200 EET m=+6.327596929 " } 
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117588
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Да. Это копи-паста из стандартной документации по Go-хомяку.

Я тоже ее вчера взял и начал делать функцию текущего даты-времени. Но уже было поздно и думал сегодня сделаю.

Почему эта документация выглядит как-то по уродски? Язык - хороший.
Но пишут как для детей. Будто - это язык для обучения информатике в детском садике? Никто не знает?

Ты прав. Го для тех, кто не осилил даже Яву
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117615
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
   webBuilder.Configure(app => app.Use(async (ctx, _) =>
       await ctx.Response.WriteAsync(DateTime.Now.ToString()))))
   .Build().Run();
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117642
Фотография Valentin Kolesnikov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

Spring-boot решение:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

@RequestMapping("/")
@RestController
@SpringBootApplication
public class TimeApplication {

    public static void main(String[] args) {
        SpringApplication.run(TimeApplication.class, args);
    }

    @GetMapping("time")
    ResponseEntity<Map<String, Object>> getTime() {
        Map<String, Object> response = new HashMap<>();
        try {
            response.put("time", new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss").format(Calendar.getInstance().getTime()));
        } catch (Exception ex) {
            response.put("error", ex.getMessage());
            return ResponseEntity.badRequest().body(response);
        }
        return ResponseEntity.ok().body(response);
    }
}
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117836
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если я перепишу так getTime. Вроде ничего не меняется. Кода меньше.

Код: java
1.
2.
3.
4.
5.
6.
    @GetMapping("time")
    ResponseEntity<Map<String, Object>> getTime() {
        Map<String, Object> response = new HashMap<>();
        response.put("time", new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss").format(Calendar.getInstance().getTime()));
        return ResponseEntity.ok().body(response);
    }
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117868
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
   webBuilder.Configure(app => app.Use(async (ctx, _) =>
       await ctx.Response.WriteAsync(DateTime.Now.ToString()))))
   .Build().Run();


Красиво. И асинхронщина - уже часть языка C# ?
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117883
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
И асинхронщина - уже часть языка C# ?

Так уже почти 10 лет - начиная с пятой версии.
...
Рейтинг: 0 / 0
Тяпничный http-echo-time-server на разных языках разработки
    #40117931
Фотография Valentin Kolesnikov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton
Если я перепишу так getTime. Вроде ничего не меняется. Кода меньше.

Код: java
1.
2.
3.
4.
5.
6.
    @GetMapping("time")
    ResponseEntity<Map<String, Object>> getTime() {
        Map<String, Object> response = new HashMap<>();
        response.put("time", new SimpleDateFormat("yyyy-mm-dd'T'hh:mm:ss").format(Calendar.getInstance().getTime()));
        return ResponseEntity.ok().body(response);
    }



Так тоже будет работать.
...
Рейтинг: 0 / 0
25 сообщений из 27, страница 1 из 2
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Тяпничный http-echo-time-server на разных языках разработки
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали тему (1): Анонимы (1)
Читали форум (1): Анонимы (1)
Пользователи онлайн (7): Анонимы (5), Bing Bot, Yandex Bot 2 мин.
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]