LINUX.ORG.RU

Golang HTTP Middleware

 , ,


0

3

Пошаговая инструкция понимания Golang HTTP Middleware.

Вариант №1:

  1. Надо представить сервер как процесс с STDIN/STDOUT.
  2. Надо понять что STDIN/STDOUT обслуживаются объектами созданными по лекалу интерфейсов. И названными r/w. Ну и порядок перевернут w,r в сигнатуре.
  3. Вот ту ключевое - обрабатывается ОДНОЙ ФУНКЦИЕЙ которую вызывают. ТОЧКА.
  4. А дальше расширить понимание, что Эту функцию можно вызывать каскадом.
  5. И последнее уже переходное, то MiddleWare КОНСТРУИРУЕТ функцию. По этому каждый этап MiddleWare Возвращает валидный ServerHTTP! Который либо Пишет сам. Либо завет чужой хендлер по замыканию.

Вариант №2:

  1. Представить HTTP сервер как UNIX Процесс с STDIN/STDOUT.
  2. Понять что STDIN и STDOUT обрабатываются через инстансы созданные по «чертежам интерфейсов». STDIN - Resquest, STDOUT - Response. (STDIN=Request=Read):(STDOUT=Response=Write).
  3. Запрос обрабатывается одной функцией. Точка.
  4. Расширить понимание, функцию можно вызывать каскадом.
  5. Middleware не функция для вызова, это функция которая ВОЗВРАЩАЕТ функцию для Вызова.

🎆 Отливаем в бронзе, лаконичная формула от Qwen:

Middleware в Go — это не хук. Это фабрика функций.

Она принимает Handler, возвращает Handler, а внутри — через замыкание — решает, когда и как вызвать следующий.

🎆 От ChatGPT:

Middleware в Go — это не механизм перехвата, а функция высшего порядка, которая принимает handler и возвращает новый handler, формируя цепочку через замыкания и управляя моментом вызова следующего обработчика.

🎆 От DeepSeek:

Middleware в Go — это не цепочка вызовов. Это фабрика, которая конструирует один метод ServeHTTP как матрёшку из замыканий, где каждый слой хранит ссылку на следующий в своей области видимости.

🎆 От Grok:

Middleware в Go — это фабрика функций. Она принимает http.Handler, возвращает http.Handler, а внутри через замыкание решает, когда и как вызвать следующий (или прервать цепочку). Это не «добавление хука». Это оборачивание одного обработчика в другой, создающее конвейер (pipeline).

📀 P.S.

На самом деле пример с методом это максимальное упрощения для уменьшения количества сущностный в схеме. Обработка происходит не просто через вызов функции, а через инстанс реализующий интерфейс Hanler. Да и на самом деле этот интерфейс содержит, то всего одну функцию.

type HandlerFunc func(http.ResponseWriter, *http.Request)

func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    f(w, r)
}

По этому функцию можно приводить к типу этого интефейса Hanlder. Изюминка заключается в том, что http.HandlerFunc(hello) - это не вызов метода. Это приведение к типу (type conversion) HandlerFunc.

🎆 Полировка от DeepSeek:

Благодаря http.HandlerFunc любую функцию с сигнатурой (ResponseWriter, *Request) можно привести к типу http.Handler, что делает оборачивание элегантным и типобезопасным.

🎆 Полировка от Qwen:

http.HandlerFunc(f) — это статический адаптер, который превращает функцию в объект, реализующий интерфейс, через навешивание метода на тип-функцию.

🎆 Полировка от ChatGPT:

В выражении http.HandlerFunc(hello) происходит приведение обычной функции к функциональному типу HandlerFunc, что позволяет этому значению получить метод ServeHTTP и тем самым реализовать интерфейс http.Handler.

🎆 Полировка от Grok:

http.HandlerFunc — статический адаптер, который позволяет любой функции с правильной сигнатурой стать http.Handler и участвовать в этой цепочке.

Middleware в Go — это фабрика функций.

Она принимает http.Handler, возвращает http.Handler, а внутри через замыкание конструирует новый ServeHTTP, который решает, когда вызвать следующий слой.

Это не «добавление хука», а оборачивание одного обработчика в другой, создающее гибкий конвейер (pipeline).

📀📀 P.P.S.

Что еще важно, так как в итоге ServeHTTP метод который вызывается для обработки запроса представляет собой наслоение замыканий «кольцами», то из любого кольца можно принят решение о немедленном выходе, ни погружаясь дальше. Вот так вот изящно формируется в Golang единственная функция обработчик, которая в себе имеет сколь хватит памяти уровней, и к каждый уровень это Middleware или отдельный метод. Метод либо прерывающий цепочку и отвечающий в http.Response, или вызывающий следующий метод, переходя в новый слой.

🎆 Полировка от Qwen:

Middleware в Go — это управляемый конвейер с возможностью аварийной остановки. Каждый слой обладает полным правом вето: он может обработать запрос самостоятельно и завершить цепочку, не беспокоя следующие уровни.

🎆 Полировка от DeepSeek:

В итоге формируется единая функция-обработчик, которая в себе содержит сколько угодно уровней логики, а каждый уровень — это либо точка остановки, либо переход на следующий уровень.

🎆 Полировка от ChatGPT:

Итоговый ServeHTTP — это одна функция, собранная как композиция вложенных замыканий (цепочка middleware), где каждый слой принимает решение: вызвать следующий обработчик или завершить обработку немедленно.

В Go HTTP middleware формирует один итоговый обработчик через композицию замыканий. Каждый слой получает управление и решает: вызвать следующий обработчик или завершить обработку, сформировав ответ. Таким образом, вся цепочка — это одна функция с контролируемым потоком выполнения.

🎆 Полировка от Grok:

В результате вся обработка запроса — это одна функция, внутри которой спрятана вся цепочка замыканий, и поток выполнения полностью контролируется на каждом слое. Это один из самых элегантных и мощных паттернов в стандартной библиотеке Go.

🐳 Итоговая формула (собранная из цитат) от DeepSeek:

Middleware в Go — это не цепочка вызовов и не система перехвата событий. Это фабрика, которая конструирует единый метод ServeHTTP как 🪆 матрёшку из замыканий.



Последнее исправление: lbvf50txt (всего исправлений: 11)
Ответ на: комментарий от beastie

В принципе, да, вы правы. В поисках единомышленников и дополнений. Вот я по началу разозился на вас, а потом зашел к вам на сайт, и был поражен красотой визуализации графа кода Морзе.

Правда, не понятно - что это за переходы и какая в них логика. Но все равно красиво.

Ради таких моментов и выходят «в свет».

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Вы сами себе дайте ответ зачем вы наполняете форум бессмысленными короткими сообщениям.

lbvf50txt
() автор топика
Ответ на: комментарий от beastie

Понимаете, обработка HTTP запросов в Golang - это один из самых сложный вопросов. Он идиоматичен до одури. Там смешалось всё: интерфейсы, замыкания, объекты, модель ввода/вывода.

Получается такая крупная конструкция, которую фиг разберешь при быстром прочтении: handler, HandleFunc, HalderFunc (Ага!). И этот клубок надо распутать, если вы не хотите полностью полагаться на LLM генерированный код.

Еще сверху можно добавить мултиплексторы, которые зовутся роутеры в других языках, которые тоже хендлеры. Требуется найти точку с которой начинать весь этот разбор. А эта точка сигнатура ServeHTTP.

lbvf50txt
() автор топика
Ответ на: комментарий от lbvf50txt

если вы не хотите полностью полагаться на LLM генерированный код.

начните писать сами и советуйтесь только с мануалами. Тогда всё что сейчас намешано в кучу, постепенно разложиться по своим местам. Сейчас очевидная мешанина из Go, отдельных фреймворков и бесед с ИИ-шкой

MKuznetsov ★★★★★
()
Ответ на: комментарий от lbvf50txt

Там всё, как два пальца об асфальт. Го – это один из самых скучных (в хорошем смысле), понятных и предсказуемых языков. Конкретный пример, что ты не понимаешь можно?

beastie ★★★★★
()
Ответ на: комментарий от beastie

Давайте перевернем вопрос. А что вы понимаете как обрабатывается HTTP в Golang?

А то вы вышли с таким коленцом эксперта и знатока. Расскажите общую схему обработки запроса и работы Middleware. С удовольствием послушаю.

lbvf50txt
() автор топика

Нужен тег «я познаю мир».

Ну хорошо, с middleware ты познакомился, теперь можно ещё и про интерцепторы почитать.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от beastie

С огромной долей вероятности пользователи рассказывающие про «Go скучный язык» - никогда на нем серьезно не писали. Возможно прошли Go Tour и написали FuzzBizz. И то не факт.

В Go полно идиоматический конструкций, таких как:

  • Использование буферов переданных по указателю в интерфейсах.
  • Использование именованных return заполняемых через замыкания в defer.
  • Использование фабрик возвращающих многослойные обработчики замыканий.

Вы «балтуете», от вас ни одного технического замечания, добавления, поправки. Скорей всего вы сами нифига не знаете про Go. Так вышли продемонстрировать экспертность через обесценивания.

  • Зачем написал?
  • Всё просто!
  • Ты чё не понимаешь?

Ага. Конструктивно.

lbvf50txt
() автор топика
Ответ на: комментарий от Nervous

Форумы для этого и нужны. Для «познавания мира» и обмена «инсайтами». Это форумы здоровых людей. Есть еще форумы токсиков, где пытаются задеть и показать свою важность через обесценивание короткими фразами.

И реализация Middleware не всегда идет через формирование одного метода замыканиями, есть и другие способы. Вы путаете патерн и способ его реализации.

lbvf50txt
() автор топика

все эти миддлвари конечно замечательно, но про них можно забыть.

Потому что к руководству в Го вместо авторов подобных глубоко продуманных архитектур пришли бездари, которые начали все переписывать на генерики - потому что в расте на всех кормушек не хватает, а по-другому они не умеют))

Lrrr ★★★★★
()
Ответ на: комментарий от lbvf50txt

Для «познавания мира» и обмена «инсайтами»

Да, но общественно значимыми. Твоё личное познавание и инсайты по поводу вещей которые являются общим местом никого не интересуют.

no-such-file ★★★★★
()

Я не понимаю, как можно конструировать функцию? Это ЛИСП что ли? Спроси у ИИ’шки.

seiken ★★★★★
()

Угадал автора по началу темы. Кстати, его темы и раньше напоминали выхлоп бредогенераторов. Может быть он ими и пользовался, а может просто похож.

firkax ★★★★★
()

Сказка «Гошка». Написало гугло язычок для идиотов. Вырос язык круглый, как репа и простой, как двери. Набежали идиоты, тянут-потянут, вытянуть не могут. Позвали на помощь дипсика. Идиоты за гошку, дипсик за идиотов, тянут-потянут, вытянуть не могут. Позвали на помощь квена. Квен за дипсика, дипсик за идиотов ну в общем мне надоело, дальше сами понимаете.

thesis ★★★★★
()
Последнее исправление: thesis (всего исправлений: 2)

Go в принципе неподъемный для новичков там все сделано гениально просто, но при том понять без фундамента UNIX и проработанного OOP не возможно.

Формируется обработчик как одна функция, но это функция идет слоями, как луковица или как матрешка. И на каждом слое можно выбрать или углубятся дальше или выходить из «луковицы» вовсе. Такой генерируется многоуровневый почти замкнутый объект. Но и это блин еще не все, он передает как бы функции. Но это не фига не функции, это функции приведенные к интерфейсу, и у этой функции есть своя функция которая вызывает сама себя!

О как! О как! Как о?

Нормально. Вообще нормально.

Потом в форуме выходят типы, которые больше одного предложения тексты не публикуют. И начинают обесценивать или разбор механизма, или язык Go.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от lbvf50txt

Формируется обработчик как одна функция, но это функция идет слоями, как луковица или как матрешка. И на каждом слое можно выбрать или углубятся дальше или выходить из «луковицы» вовсе. Такой генерируется многоуровневый почти замкнутый объект. Но и это блин еще не все, он передает как бы функции. Но это не фига не функции, это функции приведенные к интерфейсу, и у этой функции есть своя функция которая вызывает сама себя!

Да, и еще будет важным добавить, что каждый слой этого обработчика-луковицы 🧅 или обработчика-матрешки 🪆, представляет собой отдельную функцию созданную как замыкание где доступ к следующему слою идет через аргумент функции конструктора.

Шаблон называется «Композиция через замыкания».

// Jon Bodner: Learning Go an Idiomatic Approach to the Real World Go Programming
// Page: 252, Chapter 11: The Standard Library;

func RequestTimer(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		h.ServeHTTP(w, r)
		end := time.Now()
		log.Printf("request time for %s: %v", r.URL.Path, end.Sub(start))
	})
}

var securityMsg = []byte("You didn't give the secret password\n")

func TerribleSecurityProvider(password string) func(http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.Header.Get("X-Secret-Password") != password {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write(securityMsg)
				return
			}
			h.ServeHTTP(w, r)
		})
	}
}

Сказки о том, что Go - «скучный язык», или примитивный язык для «студентов». Это пересказывание давно услышанного сравнения с С++, которой используется как повод для самовозвеличивание через обесценивания.

Так как в Go реализовали свой внутренний планировщик, то масса вопросов разработки параллельной обработки запросов упростилась в сравнении с С++. Так как все перетянули в одно адресное пространство и реализовали Горутины с Каналами - тем самым сильно упростив передачу данных между разными тредами исполнения. Убрали часть низкоуровневых манипуляций под капот, реализовали CSP Communication Sequential Processes модель от Tony Hoare из 1974 года.

В этом контексте Go - простой. Но до этого контекста большинство форумных оценщиков не доходит. Так услышали где-то и повторяют, классно же чувствовать себя «авторитетом».

  1. Go очень идиоматичный, идиомы завязаны на ООП.
  2. Go требовательный к знанию устройства ОС.
  3. Go требовательный к Алгоритмической подготовке, чтоб просто понимать когда есть смысл запускать Горутины и как они переговариваются друг с другом.

И все перетекает из одного в другое. И всё это тяжеловесное (в плане сложности) великолепие имеет только один смысл - оптимизация потребления ресурсов. Либо если нет денег оплачивать дорогой хостинг; или такой вал запросов, что оборудование уже не справляется физически. По этому в Golang есть еще свой Aссемблер с синтаксисом из Plan9 - чтоб уж оптимизировать вообще до предела.

Но в форумах «срезают» рассказом - у Го есть Сборщик Мусора, он «останавливает мир». А ничего, что Го работает в ОС c Preemptive Multitasking? Конечно ничего, критики таких слов не знают. И что любой процесс вытеснятся и «замораживается» вне зависимости есть у него сборщик мусора в рантайме, критики тоже не знают.

lbvf50txt
() автор топика
Ответ на: комментарий от lbvf50txt

Да, и еще будет важным добавить, что каждый слой этого обработчика-луковицы

Лисп несколько десятилетий назад так работал. А сейчас дошло и до Go и Javascript.

Но в форумах «срезают» рассказом - у Го есть Сборщик Мусора, он «останавливает мир». А ничего, что Го работает в ОС c Preemptive Multitasking?

Вот есть у тебя ОС с планировщиком, который гарантирует получение кванта времени раз в пол миллисекунды и есть устройство, которое раз в миллисекунду что-то отправляет. Причём если за миллисекунду не прочитать, значение утеряно. На языках без сборщика мусора можно написать надёжный обработчик. На Го в общем случае нет.

monk ★★★★★
()
Ответ на: комментарий от lbvf50txt
func RequestTimer(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

Вот из-за вагона такого шаблонного кода Go примитивный язык. Там, где в Лиспе или даже Си++ сделали бы шаблон, здесь будет вагон копипасты.

monk ★★★★★
()

Мне кажется, вы переобщались с нейронками. И они на вас вредно действуют. Вот, самый формаn «формулировка от того, полировка от сего» вызывает ощущение сырости и нероработанности, вместо ценного личного озарения, какая-то копия чужого диалога с бредогенератором. Было бы мне интересно с чатгопотой пообщаться, я б так и сделал, без вашего посредничества.

ugoday ★★★★★
()
Ответ на: комментарий от monk

Причём если за миллисекунду не прочитать, значение утеряно.

Сетевые данные буферезуются. Это надуманная ситуация, тем более вы (не)знаете как работают каналы и потоки ожидающие операции ввода/вывода. Но при этом вы так смело и безапелляционно критикуете язык Go.

P.S.

Ну это же очевидно, что Go не предназначет для Realtime систем и работает в Userspace Linux для обработки HTTP запросов. Зачем опять переводить разговоры на L1-L2 уровень модели OSI, когда в Golang и его библиотеки начинают обработку с L4.

Это все равно, что ругать автобус, за то, что автобус не джип.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 3)
Ответ на: комментарий от monk

Там, где в Лиспе или даже Си++ сделали бы шаблон, здесь будет вагон копипасты.

Вот тебе не стыдно писать такое? Честно. Просто выходить вот так и позорится, заведомо позориться. Потому что Go написан разротчиками UNIX, они как минимум «не хуже тебя» разбираюся.

И вот втирать про какую-то там «копипасту» вообще не отстреливая дупля о устройстве языков. Что есть несколько способов инкапсулировать сложность в отдельный компонент, а эта «копипаста», это как раз упрощение до максимума и редуцирование объекта до функции.

Ну просто, зачем? Зачем вылазить на заведомо проигрышную территори - заплупаться на бойцов UFC (под ними я понимаю Rob Pike создатель UTF8 и Brian Kernighan), чтоб потом просто огрести по полной.

Короче, давай без обид, я ухожу. Меня этот накал делетантизма перенарягает. Успехов в учёбе и трудовой деятельности. Пока.

lbvf50txt
() автор топика
Ответ на: комментарий от thesis

Бойцы KFC страшнее. Могут, буквально, задавить авторитетом.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

LLM это необходимый инструмент разработчика в 2026 году, ваши оскорбления «чат-гопота», «бредогенератор» - это ваше собственноручное уничтожение вас как специалиста.

Всё эра «самописцев» закончилась, хотите конкурировать - ищите баланс понимания и генерации кода. А по поводу «сырости», так это не статья, а пост в форуме - формат который подразумевает поиск решения. В данном случае короткого и запоминающегося описания механизма обработки запросов в Golang.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 1)

Не раскрыта тема атсрального вин-чуня.

slackwarrior ★★★★★
()
Ответ на: комментарий от lbvf50txt

И конкурировать я ни с кем не хочу, и насчёт долговременных последствий для психики сомнения возникают. Так что я пожалуй подожду, пусть прежде на мышах проверят. А вот оправдания небрежному стилю нет и быть не может. Если вам лень формулировать ваши мысли, то мне тем более лень вникать в поток вашего (вашего?) сознания.

ugoday ★★★★★
()
Ответ на: комментарий от lbvf50txt

Сетевые данные буферезуются.

Кто сказал про сетевые? Есть устройство, которому можно дать запрос на чтение и получить ответ. Раз в миллисекунду ответ меняется.

Ну это же очевидно, что Go не предназначет для Realtime систем и работает в Userspace Linux для обработки HTTP запросов.

Так претензии про наличие GC имеют смысл только в контексте реального времени.

monk ★★★★★
()
Ответ на: комментарий от lbvf50txt

Потому что Go написан разротчиками UNIX, они как минимум «не хуже тебя» разбираюся.

Ты с С не перепутал? Или в твоём мире Керниган и Ритчи после С написали Go?

а эта «копипаста», это как раз упрощение до максимума и редуцирование объекта до функции.

Там, где ты в Go пишешь

func RequestTimer(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		h.ServeHTTP(w, r)
		end := time.Now()
		log.Printf("request time for %s: %v", r.URL.Path, end.Sub(start))
	})
}

нормальный программист уже 30 лет может писать

(defrequest request-timer (h w r)
  (setf start (get-universal-time))
  (serve-http h w r)
  (setf end (get-universal-time))
  (format t "request time for ~a: ~a" (path h) (- start end)))

Но в Go только копипаста или внешний макропроцессор.

monk ★★★★★
()
Ответ на: комментарий от monk

Динамические языки забавные, как и статические с умным автовыведением. На них можно показывать фокусы похлеще Дэвида Копперфильда. Но я же правильно понимаю, что серебряной пули не существует и ручная статика имеет преимущества в определённых областях применения?

kaldeon ★☆
()
Ответ на: комментарий от lbvf50txt

Раз уж тут расчехлили элегантное оружие из более цивилизованной эпохи

То у бойцов ЛФК есть свой ответ как правильно организовывать код, чтобы он не превращался в нечитаемую тонну буков:

(defclass http-handler ()
  ())

(defgeneric serve-http (handler writer request))

(defmethod serve-http ((handler http-handler) writer request)
  (format t "Я работаю очень быстро!~%"))

(defclass http-handler-with-timer (http-handler)
  ())

(defmethod serve-http :around ((handler http-handler-with-timer) writer request)
  (let* ((start (get-universal-time))
	 (result (call-next-method))
	 (end (get-universal-time)))
    (format t "Время работы: ~a секунд.~%" (- end start))
    result))
ugoday ★★★★★
()

Эту тему надо закрепить! Модераторы, я серьёзно!

И потом везде кидать сюда ссылки, как доказательство деструктивного влияния нейросекты на мозг.

James_Holden ★★★★★
()
Ответ на: комментарий от monk

Есть устройство, которому можно дать запрос на чтение и получить ответ. Раз в миллисекунду ответ меняется.

Такое устройство вполне может быть и сетевым, например промышленное оборудование опрашиваемое по modbus-tcp.

James_Holden ★★★★★
()
Ответ на: комментарий от lbvf50txt
	start := time.Now()
	h.ServeHTTP(w, r)
	end := time.Now()
	log.Printf("request time for %s: %v", r.URL.Path, end.Sub(start))

Аматёрство какое-то. Джедаи делают так:

	defer func(t time.Time) {
		log.Printf("request time for %s: %v", r.URL.Path, time.Since(t))
	}(time.Now())
	h.ServeHTTP(w, r)
beastie ★★★★★
()
Ответ на: комментарий от lbvf50txt

Всё эра «самописцев» закончилась, хотите конкурировать - ищите баланс понимания и генерации кода. А по поводу «сырости», так это не статья, а пост в форуме - формат который подразумевает поиск решения.

⚠️ ВАЖНОЕ ДОПОЛНЕНИЕ:

Ручное Кодирование - важнейший этап обучения разработчика. Необходимо решить несколько тысяч Leetcode задач (или аналогов) в ручную без генерации кода. Но в коммерческом, разноплановом проекте полностью исключать LLM - это глупость и воровство времени. Сейчас разработка это микс из написания и генерации кода.

Ручное Кодирование - это навык который требуется для чтения кода. Не умеешь хорошо писать - не умеешь хорошо читать.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от beastie

Вот это вот плохой код, потому что он разрывает нить логических рассуждений и вводит в решение задачи абстракции которые для решения этой задачи не нужны: defer и замыкание.

Это и есть самый насоящий «любительский код», когда любитель показывает свою «крутизну», не думая о читабильности кода.

// Bad code example. Adding unnecessary entities.
defer func(t time.Time) {
		log.Printf("request time for %s: %v", r.URL.Path, time.Since(t))
	}(time.Now())
	h.ServeHTTP(w, r)

А вот это вот, хороший, проф. код. Он линеен, прост, понятян, делает ровно то, что он него требуется. Ставит две засечки, и пишет разницу между ними. Когнитивная нагрузка на программиста снижается. Это код профи который решает задачу, и думает о комманде, а не показывает свою «крутизну» и не «блатует».

// Good linear code. No attention breaks.
start := time.Now()
h.ServeHTTP(w, r)
end := time.Now()
log.Printf("request time for %s: %v", r.URL.Path, end.Sub(start))

Вы начали с обесценивания, и обесцениванием продолжили. Общей схемы обработки HTTP запроса вы так и не написали. Сплошной выпендреж и показание «собственной крутости».

Мой вас совет, хотите «джигитовать» идите джигитуйте на Leetcode контесты там пишите DP на 3х мерных массивах. Или еще, что там круче? … так. Забыл. Щас. https://codeforces.com - вот.

А этот пост про инженерное дело. Где требуется понятный линейный код, а сложность уходит в проектирование системы взаимодействия модулей, вместо «жонглирования» замыканиями там где не надо. defer - он нужен для облегчения чтение, а не для добавления новой когнитивной нагрузки.

lbvf50txt
() автор топика
Ответ на: комментарий от beastie

Эксперт – не эксперт… но масло с колбасой на хлеб мне Го уже 16 лет обеспечивает. ¯_(ツ)_/¯

Стаж не тождественен классу. Зачем вы трясете этой медалькой?

Весь пост об одной теме: Обработка HTTP запроса через Middleware, и механизм превращения метода в инстанс интерфейса Handler.

У разработчика два пути. Он может писать классический структуру-объект. Может накрутить «Композицую через Замыкание» используя приведение к типу HandlerFunc.

Такого анализа от вас нет. От вас есть просто «балтование», сначала вы заявились с вопросом «Зачем пишешь?», потом рассказали «как все примитивно», потом убедили меня в том, что у вас большой стаж.

Прекрасно. Но не надо обесценивать ваших собеседников. Даже если кто-то там понял, что такое функция, а вы это поняли 28 лет наза. Не надо смеяться человеку в лицо, а уж если начали смеяться, готовтесь что вас будут лупить.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 2)
Ответ на: комментарий от beastie
// Bad code example. Adding unnecessary entities.
defer func(t time.Time) {
		log.Printf("request time for %s: %v", r.URL.Path, time.Since(t))
	}(time.Now())
	h.ServeHTTP(w, r)

При разработке проекта в котором требуется Go, а нет возможности решать через RubyOnRails - от разработчика требуется держать в голове 100 технических вопросов. О протоколах взаимодействия, метриках работы сети, о потреблении памяти Гоуртинами и так далее и тому подобное.

Вот этот код жрёт память разработчика и его внимание на не существенные детали.

  1. Когда бы вызов time.Now()? В момент когда IP (instruction pointer) дошел до defer, или в конце функции.
  2. А будут ли другие defer в функции? А сколько они едят?

А давайте поверем, а я не уверен. Тут может быть баг. Короче такой код при детально просмотре - выжрет минут 20 размышлений. А размышлять надо, потому как иногда одна пропущенная запятая перед релизом - вырубает весь модуль AI для персонажей игры. И хорошую игру заваливают отрицаетельными отзывами.

Вот это код это самый яркий пример не профессионального подхода. Когда у человека появилась игрушка - мячик. И он этот мячик пяткой отстукиват. Ох как я понял механизм работы defer. А зачем? Ты понял мододец. Зачем это вешать в боевой код, который должен быть примитивным - чем проще тем меньше багов.

Понятно - от стандартной библиотеки Go никуда не уйти, и я осоловело пол ночи вчитывался в два разных учебника (Jon Bodner и Sau Sheong Chang) пока не понял - ага, так это же метод конструируется. А потом, ага, так это же из метода конструируется инстанс интерфейса с одним методом, ага это не вызов метода, а type conresion собственной персоной.

Тут необходимо прокопать до самого основания. Но в defer - задача которого одна - закрывать открытые ресурсы, чтоб не болтались под руками. Может и не плохо так вникнуть для общей эрудиции. Но запихивать туда боевой код. Ну это большой привет команде и климату разработки.

Опять же как гимнастика - 5+, да лишним не будет. Но как боевой код - нет, ни в коем случае. В Go для этого синтаксис и упрощали, чтоб он читабельный был - без лишних вопросов.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 2)
Ответ на: комментарий от beastie

Меня вот тригернуло капитально так. Тема разговора Middleware, Jon Bonder выносит логирование в отдельный слой Middleware - чтоб можно было отключить логирование на всякий случай. В этом и смысл Middleware - модуляризация приложения, тот же SOLID. Open for extention, closed for modification.

Ну зачем в Middlware накурчивать логирование через defer? Когда цель модуля быть читабельным.

Короче, все знают, что я запальчивый до предела. Пойду, пойду пойду, пойду. Спасибо всем. До свиданья.

lbvf50txt
() автор топика
Ответ на: комментарий от Lrrr

Поддержу. Я последние годы особо за Го не слежу, но, судя по всему, изначальное ядро авторов свалило и язык начал скатываться в сторону от их философии.

urxvt ★★★★★
()
Ответ на: комментарий от lbvf50txt

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

urxvt ★★★★★
()
Ответ на: комментарий от monk

Потому что Go написан разротчиками UNIX, они как минимум «не хуже тебя» разбираюся.

Ты с С не перепутал? Или в твоём мире Керниган и Ритчи после С написали Go?

А так и было, Томпсон один из (трех) главных авторов Го. Пайк тоже к Юниксу имеет огромное отношение.
Так что, Go это продолжение UNIX. Это факт. Продолжение его философии от его же авторов.

urxvt ★★★★★
()
Последнее исправление: urxvt (всего исправлений: 1)
Ответ на: комментарий от monk
(defrequest request-timer (h w r)
  (setf start (get-universal-time))
  (serve-http h w r)
  (setf end (get-universal-time))
  (format t "request time for ~a: ~a" (path h) (- start end)))


Фу, императивщина.

urxvt ★★★★★
()
Ответ на: комментарий от lbvf50txt

Понимаете, обработка HTTP запросов в Golang - это один из самых сложный вопросов.

Напротив, это тема уровня trainee. Потому что все сводится, в сущности, к пониманию замыканий, как вам ИИшечка и подсказала.

Реально сложных проблемы в программировании две: нейминг и инвалидация кэша :)

paddlewan
()
Ответ на: комментарий от lbvf50txt

Но в defer - задача которого одна - закрывать открытые ресурсы, чтоб не болтались под руками.

Нет, у него не одна эта задача, так неправильно говорить. Посмотрите на вот этот кусочек кода, пожалуйста, и подумайте, почему так.

package main

import "fmt"

func invalid() any {
	panic("won't be recovered")

	// unreachable code
	if r := recover(); r != nil {
		return r
	}

	return nil
}

func valid() (r any) {
	defer func() {
		r = recover()
	}()

	panic("panic is for a reason")
}

func main() {
	fmt.Println("valid:", valid())
}
paddlewan
()
Последнее исправление: paddlewan (всего исправлений: 2)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.