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-ыңыз үш себептен жақсы: ол кодта көрініп тұр, оны тестке беруге болады, әрі бір бағдарламадағы екі бөлек сервер бір-біріне кедергі жасамайды.
Сабақ картасы
Өз сөзіңізбен айтыңыз
Қарамай, дауыстап немесе қағазға жазып жауап беріңіз. Жауаптары — сабақтың соңында.
GET /GET /{$}-тан несімен өзгеше?GET /read/{slug}пенGET /read/dala-ны тіркедіңіз./read/dalaқайсысына түседі және бұл жолдардың ретіне байланысты ма?- Ешқай жерде жазбасаңыз,
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 кетеді.
Жауаптар
Жауаптарды көрсету
GET /басқа бағыттарға келмеген жолдардың бәрін ұстайды, жоқ жолдарды да.GET /{$}тек түбірдің өзін ұстайды:{$}жолдың осымен бітетінін білдіреді. Онсыз мекенжайдағы кез келген қате 200 кодымен басты бетті қайтарар еді.GET /read/dala-ға, себебі ол нақтырақ. Жолдардың реті маңызды емес: бағыттауыш бірінші келгенін емес, ең дәлін таңдайды.- Оны
ServeMuxқосады. Ол осы жолға арналған барлық бағытты біледі және рұқсат етілген әдістер тізімімен 405 береді. ТізімдегіHEAD— солGET, тек денесіз, әрі Go оны өзі өңдейді.
Пікірлер (0)
Пікір қалдыру үшін кіріңіз →
Әзірге пікір жоқ. Бірінші болыңыз.