Shanraq.org Shanraq.org
Go-дағы бағыттар: қай мекенжайды кім өңдейді
IT

Go тілі: нөлден өз блогыңызға дейін 20-сабақ (барлығы 50)

Go-дағы бағыттар: қай мекенжайды кім өңдейді

Go курсының жиырмасыншы сабағы. ServeMux сұраныстарды өңдеушілерге бөледі: әдіс пен жол бір жолға жазылады, {slug} мекенжайдың бөлігін алады, {$} басты бетке бәрін ұстауға жол бермейді. 404 пен 405-ті бағыттауыш өзі береді, ал екі бағыттың қақтығысын іске қосқанда ұстайды.

Не үшін керек

Өткен сабақта өңдеуші жол мен әдісті өзі тексеретін:

if r.Method != http.MethodGet { ... }
if r.URL.Path != "/" { ... }

Бұл дәл екінші бетке дейін жұмыс істейді. Бесіншісінде мұндай өңдеуші if баспалдағына айналады, онда бір тармақты ұмытып, 404-тің орнына басты бетті беріп жіберу оңай.

Мекенжайларды кімнің жұмысы болса, сол бөлсін — бағыттауыш.

Терминді бірден келісіп алайық. Бір мекенжайдан екіншісіне баратын жол қазақша бағыт деп аталады — автобус бағыты сияқты. Ағылшынша ол route, ал оларды бөлетін нәрсе — router, қазақша бағыттауыш. Кодта route деген сөз кездеседі, сондықтан екеуін де біліп қойған жөн.

Бірден тұтас

Жаңа қалта, go mod init sabaq18, main.go:

package main

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

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "басты бет")
	})

	mux.HandleFunc("GET /about", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "автор туралы")
	})

	mux.HandleFunc("GET /read/{slug}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "мақала:", r.PathValue("slug"))
	})

	mux.HandleFunc("POST /read/{slug}/like", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "ұнады:", r.PathValue("slug"))
	})

	log.Println("http://localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", mux))
}

Іске қосып, барлық жағдайды тексеріңіз. Төменге қарамас бұрын — GET /read/dala/like дегенге жауап қандай болатынын дауыстап айтыңыз:

GET  /                     → 200  басты бет
GET  /about                → 200  автор туралы
GET  /read/dala            → 200  мақала: dala
POST /read/dala/like       → 200  ұнады: dala
GET  /read/dala/like       → 405  Allow: POST
GET  /kokek                → 404
POST /about                → 405  Allow: GET, HEAD

Кодта жол мен әдісті тексеретін бірде-бір жер қалмады — ал жауаптар бұрынғыдан дәлірек болды.

Талдау

Әдіс пен жол — бір жолда

mux.HandleFunc("GET /about", ...)

Go 1.22-ге дейін бағытқа тек жолды жазатын, ал әдісті өңдеушінің ішінде тексеретін. Енді әдіс — бағыттың бөлігі, артық if жоғалды.

Осыдан ереже шығады: бір бағыт — бір әрекет. GET /read/{slug} мақаланы көрсетеді, POST /read/{slug}/like белгі қояды. Бұл бөлек жолдар және бөлек функциялар, ішінде тармақталуы бар біреуі емес.

Елестетіп көріңіз. Жазуы бар есіктер. Мекемеде бір терезеден бәрін сұрамайды: әрқайсысының үстінде мұнда не істелетіні жазылған. Сіз жазуды оқып, керегіне барасыз.

{slug} — мекенжайдың бөлігі мән ретінде

mux.HandleFunc("GET /read/{slug}", func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "мақала:", r.PathValue("slug"))
})

Үлгідегі фигуралық жақша: мұнда кез келген мән тұрады, оны slug деп ата дегенді білдіреді. Оны r.PathValue("slug") әдісімен алады.

Жақшаның ішіндегі ат сіздікі — {id} не {name} деп атаңыз, тек PathValue сол атты сұраса болды. Бұл сайтта мақаланың мекенжайы дәл солай құрылған: /read/go-marshruttar.

{$} — әйтпесе басты бет бәрін ұстайды

Go-да GET / бағыты «басты бет» дегенді емес, «басқа ешкім алмағанның бәрі» дегенді білдіреді. Өткен сабақтағы сол жағдай.

Өзіңіз тексеріңіз: GET /{$}-ті GET / деп ауыстырыңыз — сонда /kokek 404-тің орнына 200 кодымен басты бетті алады.

Үлгінің соңындағы {$} «жол осында бітеді» дегенді білдіреді. GET /{$} — тек басты беттің өзі, басқа ештеңе емес.

Елестетіп көріңіз. «Қалғанының бәрі» деген жәшік. Ондай жәшік шынымен қалғанының бәрі салынып тұрғанда пайдалы. Ал үстіне «кіріс хаттар» деп жазсаңыз, оған пошта да, қоқыс та түсе бастайды, әрі мұны бірден байқамайсыз.

Екеуі де келсе, қайсысы жеңеді

Тіркеу реті маңызды емес. Нақтырақ бағыт жеңеді:

mux.HandleFunc("GET /read/{slug}", ...)   // кез келген мақала
mux.HandleFunc("GET /read/dala", ...)     // дәл осы

/read/dala екіншісіне түседі, /read/kokek — біріншісіне, әрі оларды қай ретпен жазғаныңыз маңызды емес.

Ал екі бағыт бірдей нәрсені ұстаса — бағдарлама іске қосылмайды:

panic: pattern "GET /read/{name}" conflicts with pattern "GET /read/{slug}":
	GET /read/{name} matches the same requests as GET /read/{slug}

Іске қосылғандағы panic дөрекі көрінеді, бірақ бұл — сыйлық: бағыттар қақтығысын прод ортадағы оқырман емес, сіз өз машинаңызда таптыңыз.

Елестетіп көріңіз. Айырықтағы екі бірдей нұсқағыш. Оларды алып тастамайынша жүруге болмайды — көлік кездейсоқ бұрылып кетпей, бірден тоқтағаны дұрыс.

404 пен 405-ті бағыттауыш өзі береді

Бірде-бір өңдеушіде WriteHeader(404) да, Allow да жоқ. Бірақ жауаптар дұрыс, себебі ServeMux барлық бағытты біледі: жол ешқайсысына келмесе — 404; жол келді де, әдіс келмесе — рұқсат етілгендер тізімімен 405.

Тізімге назар аударыңыз: Allow: GET, HEAD. HEAD өзінен-өзі пайда болды — бұл сол GET, тек денесіз, әрі Go оған сіздің орныңызға жауап береді.

Бағыт көбейгенде

Ондаған тіркеу жолынан кейін main оқылмай қалады. Әдеттегі тәсіл — бағыттарды дайын бағыттауыш қайтаратын бөлек функцияға шығару:

func routes() *http.ServeMux {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /{$}", home)
	mux.HandleFunc("GET /about", about)
	mux.HandleFunc("GET /read/{slug}", article)
	return mux
}

Сонда main-де бір жол қалады, ал сайттың барлық мекенжайы бір жерде, тізім болып көрінеді. Әрі сол тізімді нағыз серверді көтермей-ақ тестке беруге болады.

Екінші аргументте тұрған nil

http.ListenAndServe(":8080", mux)

Үшінші сабақтан бері онда nil тұратын. Енді оның нені білдіргенін айтуға болады: «әдепкі бағыттауышты ал» — mux-сыз http.HandleFunc жазылатын сол бағыттауышты.

Өз mux-ыңыз үш себептен жақсы: ол кодта көрініп тұр, оны тестке беруге болады, әрі бір бағдарламадағы екі бөлек сервер бір-біріне кедергі жасамайды.

Сабақ картасы

Сабақ картасы: бір кіреберіс, бірнеше белгіленген есік, бағыттауыш таңдайды

Өз сөзіңізбен айтыңыз

Қарамай, дауыстап немесе қағазға жазып жауап беріңіз. Жауаптары — сабақтың соңында.

  1. GET / GET /{$}-тан несімен өзгеше?
  2. GET /read/{slug} пен GET /read/dala-ны тіркедіңіз. /read/dala қайсысына түседі және бұл жолдардың ретіне байланысты ма?
  3. Ешқай жерде жазбасаңыз, Allow: GET, HEAD қайдан шығады?

Тапсырма

Міндетті. Блогты бағыттарға бөліңіз: GET /{$} — мақалалар тізімі, GET /read/{slug} — мекенжайы бойынша бір мақала, GET /about — өзіңіз туралы. Мақалаларды құрылымдар тілімінен алыңыз, ал ондай мекенжай болмаса — өз мәтініңізбен 404 беріңіз. Барлық жағдайды curl -i арқылы тексеріңіз, POST /about те кіреді.

Қалауыңызша.

  • GET /{$}-ті GET / деп ауыстырып, /kokek не болатынын қараңыз. Кейін кері қайтарыңыз.
  • Бірдей нәрсені ұстайтын екі бағыт тіркеп, panic хабарын толық оқыңыз.
  • GET /read/{slug}/{part} қосып, екі ат үшін де PathValue-ге не келетінін қараңыз.

Блогта қайда тұрады

Блогтың мекенжайлары енді нағызға жақын: /, /about, /read/{slug}. Тек мазмұны жетіспейді — әзірге жауапқа бет емес, жол кетеді.

Келесі сабақта барлық бағыт үшін бірдей істі істейтін орама пайда болады: журнал, жауап уақыты, тексеру. Одан кейін — үлгілер, fmt.Fprintln орнына денеге HTML кетеді.

Жауаптар

Жауаптарды көрсету
  1. GET / басқа бағыттарға келмеген жолдардың бәрін ұстайды, жоқ жолдарды да. GET /{$} тек түбірдің өзін ұстайды: {$} жолдың осымен бітетінін білдіреді. Онсыз мекенжайдағы кез келген қате 200 кодымен басты бетті қайтарар еді.
  2. GET /read/dala-ға, себебі ол нақтырақ. Жолдардың реті маңызды емес: бағыттауыш бірінші келгенін емес, ең дәлін таңдайды.
  3. Оны ServeMux қосады. Ол осы жолға арналған барлық бағытты біледі және рұқсат етілген әдістер тізімімен 405 береді. Тізімдегі HEAD — сол GET, тек денесіз, әрі Go оны өзі өңдейді.

Дереккөздер

Мәтінде қате не теру қатесі кездессе, бізге айтыңыз

Тапсырманы тексеру

Алдымен VS Code-та шешіп, іске қосыңыз — редактор қатені сол жерде көрсетеді. Дайын шешімді осында қойыңыз. Тексеретін — модель: ол қатені атап көрсетеді, бірақ дайын жауапты бермейді.

Тексеру үшін кіру керек. Кіру

Пікірлер (0)

Әзірге пікір жоқ. Бірінші болыңыз.