Skip to main content

สรุปสั้น ๆ

สวัสดีครับ! วันนี้เราจะมาใช้ Go เจ้าภาษาที่มีความนิยมในการนำมาพัฒนาเว็บต่าง ๆ ด้วยฟีเจอร์หลายอย่างที่ออกแบบมาสำหรับการทำ Web Service (แต่ไม่ได้ใช้ทำได้แค่ Web Service เท่านั้นนะ จะเอาไปทำ CLI แอป โปรแกรมที่ใช้บนคลาวด์ หรือ ด้าน Network ก็ได้) ในบทความนี้ เราจะมาดูว่าถ้าเป็นมือใหม่หัด Dev อยากลองทำ Web Service ด้วย Go จะเริ่มยังไงดี มาเริ่มกันเล้ย!

เขียนโดย
Sirasit Boonklang (Aeff)
Tech and Coding Consultant

บทความนี้ตีพิมพ์ และ เผยแพร่เมื่อ 16 กุมภาพันธ์ 2566

ก่อนที่เราจะเป็นวัยรุ่นใจร้อนเขียนโค้ดเลย เรามาทำความเข้าใจสิ่งสำคัญก่อนว่า Web Service คืออะไร

Web Service คือ วิธีสำหรับสองโปรแกรมที่แตกต่างกันในการสื่อสารระหว่างกันผ่านอินเทอร์เน็ต

โดยในการสร้าง Web Service ด้วย Go สามารถทำได้หลายแบบไม่ว่าจะเป็นใช้ Framework หรือจะใช้เป็น Standard Package อย่าง net/http ที่มาพร้อมกับ Go อยู่แล้วก็ได้ ในแพ็คเกจนี้มีเครื่องมือที่จำเป็นทั้งหมดในการสร้าง Web Service รวมถึงการกำหนด Route การให้บริการไฟล์ และการจัดการ HTTP requests/responses ต่าง ๆ

เมื่อเราได้รู้จักกับ Web Service และเหตุผลในการใช้ Go เบื้องต้นกันไปแล้ว มา! มาลุยโค้ดกัน 🚀

ในการสร้างโปรเจกต์ Go เราจะต้องสร้างไฟล์ go.mod ในการเก็บ Path หรือเวอร์ชันต่าง ๆ ก่อนโดยใช้คำสั่ง go mod init <path_name> เช่น go mod init github.com/<username>/simple-web-service-go หลังจากนั้นจะได้ไฟล์ go.mod ขึ้นมา

จากนั้นเรามาเริ่มจากการสร้างเว็บเซิร์ฟเวอร์พื้นฐานที่ return คำว่า “Hello, World!” เมื่อเราเรียกใช้ผ่าน HTTP ที่เป็น localhost:8081 เพื่อเอาฤกษ์เอาชัยกันก่อน สร้างไฟล์ main.go แล้วเขียนโค้ดตามด้านล่างเลย

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, World!")
	})

	http.ListenAndServe(":8081", nil)
}

โค้ดด้านบนคือเอาไว้ทำ HTTP server ที่รอการทำงานเมื่อมีการร้องขอมาที่พอร์ต 8081 ส่วนของ func http.HandleFunc คือฟังก์ชันที่ใช้จัดการกับ request และ response

โดยเมื่อเราเราเขียนโค้ดเสร็จรันด้วยคำสั่ง go run main.go

แล้วไปที่ localhost:8081 จะมีการตอบกลับมาว่า “Hello, World!”

เดี๋ยวผมขอกลับมาอธิบาย ฟังก์ชัน http.HandleFunc ให้ละเอียดยิ่งขึ้นหน่อยนะครับ ฟังก์ชันนี้ใช้สอง Argument ที่เป็น string มันจะแสดง Route URL ที่จะจับคู่กันกับฟังก์ชัน เมื่อมี Request ที่เข้ามาตรงกับ Route หรือ Path ที่ตั้งไว้มันก็จะทำงานในฟังก์ชันนั้น โดยฟังก์ชันนี้ เรากำลังใช้ Route URL ที่เป็น Root หรือ (”/”) นั้นเอง และ ฟังก์ชันรับ http.ResponseWriter และ http.Request เป็นอาร์กิวเมนต์

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request)

http.ResponseWriter ใช้เพื่อเขียนการตอบกลับกลับไปยัง Client ในกรณีนี้เรากำลังใช้ฟังก์ชัน
fmt.Fprintf เพื่อเขียนข้อความ “Hello, World!” ตอบกลับ

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
})

http.Request เมื่อมีข้อมูลเกี่ยวกับคำขอที่เข้ามา เช่น HTTP method (GET, POST เป็นต้น) Header และข้อมูลใด ๆ ที่ส่งมาพร้อมกับ Request

ต่อมาเรามาเรามาสร้าง Path เพิ่มเติม

ตอนนี้เรามีเว็บเซิร์ฟเวอร์พื้นฐานและทำงานแล้ว เรามาเพิ่มฟังก์ชันกันหน่อย มาสร้างอีก Endpoint ที่เป็น Path สำหรับทักทาย แล้วรับค่าจาก user มาด้วยกันหน่อยดีกว่า

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
    })

    http.HandleFunc("/greet/", func(w http.ResponseWriter, r *http.Request) {
        name := r.URL.Path[len("/greet/"):]
        fmt.Fprintf(w, "Hello, %s!", name)
    })

    http.ListenAndServe(":8080", nil)
}

ในโค้ดนี้ เราได้เพิ่ม Endpoint ใหม่ที่ชื่อว่า (“/greet/”) มีการรับ Parameter ใน URL ด้วย โดยการใช้ตัวแปร r.URL.Path สำหรับเอา URL ของ Route แบบเต็มมาก่อน จากนั้นใช้ฟังก์ชัน len เพื่อรับความยาวของ “/greet/” จากนั้นเแบ่งส่วนเพื่อรับชื่อจาก URL Route

เราสามารถทดสอบได้โดยเข้าไปที่ http://localhost:8081/greet/borntodev ในเว็บเบราว์เซอร์ แล้วระบบจะการตอบกลับว่า “Hello, borntoDev!”

ต่อมาเรามาเพิ่มฟีเจอร์เข้าไปเพิ่มสักหน่อย อย่างเช่น Middleware, Goroutine และการสร้างหน้า HTML ขึ้นมา

func loggingMiddleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Printf("[%s] %s %s\n", time.Now().Format("2006-01-02 15:04:05"), r.Method, r.URL)
    next.ServeHTTP(w, r)
  })
}

แต่ละพีเจอร์ที่เพิ่มเข้ามามีอะไรบ้างมาดูกันครับ

  1. Middleware: มิดเดิลแวร์เป็นฟีเจอร์ที่ช่วยเป็นเหมือนกำแพงในการสกัดกั้น Request ที่เข้ามาและไปประมวลผลต่อเพิ่มเติมก่อนที่จะส่งต่อไปยัง main handler function  เช่น เราสามารถใช้มิดเดิลแวร์เพื่อ แสดง Log ของ Request ที่เข้ามา ใช้ทำ Authentication หรือ Authorization ในการยืนยันตัวหรือการตรวจสอบสิทธิ์ ไปจนถึงแก้ไขส่วน Request header
  2. Goroutines: Goroutines สามารถใช้จัดการ Request หลายรายการพร้อมกันในส่วนประมวลผลเดียวกัน ทำให้เราสามารถรีดประสิทธิภาพ และ ความสามารถในการสเกล Web Service ของเราได้ใน Go
  3. Templates: เราสามารถสร้างหน้า HTML แบบไดนามิกและเนื้อหาอื่นๆ ในหน้าเว็บได้ โดยใช้เทมเพลตเพื่อสร้างเลย์เอาต์ที่ใช้ซ้ำได้บนหน้าเว็บ และเติมข้อมูลจากโค้ด Go

แล้วโค้ดแต่ละบรรทัดคืออะไรหละ

loggingMiddleware: เป็นฟังก์ชันมิดเดิลแวร์ที่ใช้ http.Handler เป็น Argument และส่งคืน http.Handler ใหม่ ฟังก์ชันนี้มันจะ Log request ที่เข้ามามาแสดงในคอนโซล จากนั้นส่ง Request ไปยัง Handler ถัดไปและเชื่อมต่อโดยใช้ next.ServeHTTP(w, r) การทำแบบนี้มันจะทำให้เราสามารถประมวลผล Request ที่เข้ามาก่อนที่จะส่งต่อไปยัง handler function

package main

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

func loggingMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("[%s] %s %s\\n", time.Now().Format("2006-01-02 15:04:05"), r.Method, r.URL)
		next.ServeHTTP(w, r)
	})
}

func greetHandler(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Path[len("/greet/"):]
	tmpl, err := template.New("greet").Parse("<html><body><h1>Hello, {{.}}!</h1></body></html>")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = tmpl.Execute(w, name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

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

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, World!")
	})

	mux.HandleFunc("/greet/", greetHandler)

	server := &http.Server{
		Addr:         ":8080",
		Handler:      loggingMiddleware(mux),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	err := server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}
}

greetHandler: เป็นฟังก์ชันตัวจัดการที่ใช้ http.ResponseWriter และ http.Request เป็น Argument ฟังก์ชันนี้จะแยกพารามิเตอร์ name มาจาก URL โดยใช้ r.URL.Path[len(“/greet/”):] จากนั้นใช้แพ็คเกจ html/ template เพื่อสร้างหน้า HTML พร้อมคำทักทาย ผลลัพธ์จะถูกเขียนโดยใช้ tmpl.Execute(w, name)

func greetHandler(w http.ResponseWriter, r *http.Request) {
	name := r.URL.Path[len("/greet/"):]
	tmpl, err := template.New("greet").Parse("<html><body><h1>Hello, {{.}}!</h1></body></html>")
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
  err = tmpl.Execute(w, name)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

main: ในฟังก์ชัน main จะมีการใช้ http.NewServeMux() เพื่อสร้าง ServerMux หรือ HTTP request multiplexer สำหรับจัดการ HTTP Request และกำหนด Route จากนั้นเพิ่ม HandleFunc สองตัวให้กับ mux โดยใช้ mux.HandleFunc() ตัวจัดการแรกเพียงแค่ Reture ข้อความกลับไปว่า “Hello, World!” เมื่อมี Requtest เข้ามาที่ (“/”) ในขณะที่ตัวจัดการที่สองเรียกฟังก์ชันที่มี Request เข้ามาที่ (“/greet/”)

  mux := http.NewServeMux()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, World!")
	})

	mux.HandleFunc("/greet/", greetHandler)

	server := &http.Server{
		Addr:         ":8082",
		Handler:      loggingMiddleware(mux),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

server: http.Server เป็นตัวกำหนดตัวเลือกเพิ่มเติมสำหรับเว็บเซิร์ฟเวอร์ เช่น พอร์ต (:8080) หมดเวลาการอ่าน 5 วินาที และหมดเวลาเขียน 10 วินาที นอกจากนี้ยังระบุฟังก์ชัน loggingMiddleware เป็นตัวจัดการหลักสำหรับ Request ที่เข้ามา ซึ่งหมายความว่า Request ทั้งหมดจะได้รับการประมวลผลโดยมิดเดิลแวร์ก่อนที่จะส่งต่อไปยังฟังก์ชันตัวจัดการหลักนั้นเอง

server := &http.Server{
		Addr:         ":8082",
		Handler:      loggingMiddleware(mux),
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	err := server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}

เมื่อลองทำการรันและทดสอบดูก็จะเห็นได้ว่าจะมี log แสดงในส่วนของ console เรียบร้อยแล้ว

หากใครที่จะเริ่มต้นเรียนรู้ภาษา Go และเรียนรู้การใช้งาน Azure App Service อยากจะบอกดังๆว่า เรามีคอร์สฟรีที่ไม่ควรพลาด

Introduction to Go Programming Language

ใครยังไม่เคยลองใช้งานภาษา Golang มาลองดูกันสักนิดดีกว่า…ว่าเรียน Golang แล้วเราสามารถนำเอาไปใช้งานร่วมกับอะไรได้บ้าง ?
เรียกได้ว่าเป็นอีกหนึ่งภาษาที่ค่อนข้างมาแรงในช่วงนี้ ด้วยความเร็วแรงขั้นเทพที่มาพร้อมกับความสามารถที่หลากหลายทำให้ไม่น่าแปลกใจเลยที่จะเป็นหนึ่งในภาษายอดฮิตในช่วงที่ผ่านมา
 สำหรับใครที่ยังไม่ได้ลอง อย่าลืมไปลองกันดูนะครับ ไม่ผิดหวังแน่นอน แต่ถ้าใครเกร็ง ๆ กลัวว่าจะยากไปหรือเรียนรู้เองแล้วไม่เข้าใจ ไม่เป็นไรครับเพราะ borntoDev เรามีคอร์สเรียนฟรีภาษา Golang ให้ลองเรียนกันแบบง่าย ๆ เข้าใจไวไว เรียนจบได้ Certifaicate ด้วยนะ ลงทะเบียนเรียนฟรีได้ที่ : คลิกที่นี่

ระบบฝึกทักษะ การเขียนโปรแกรม

ที่พร้อมตรวจผลงานคุณ 24 ชั่วโมง

  • โจทย์ปัญหากว่า 200 ข้อ ที่รอท้าทายคุณอยู่
  • รองรับ 9 ภาษาโปรแกรมหลัก ไม่ว่าจะ Java, Python, C ก็เขียนได้
  • ใช้งานได้ฟรี ! ครบ 20 ข้อขึ้นไป รับ Certificate ไปเลย !!
เข้าใช้งานระบบ DevLab ฟรี !เรียนรู้เพิ่มเติม

เรียนรู้ไอที “อัพสกิลเขียนโปรแกรม” จากตัวจริง
ปั้นให้คุณเป็น คนสายไอทีระดับมืออาชีพ

BorntoDev

Author BorntoDev

BorntoDev Co., Ltd.

More posts by BorntoDev

เราใช้คุกกี้เพื่อพัฒนาประสิทธิภาพ และประสบการณ์ที่ดีในการใช้เว็บไซต์ของคุณ คุณสามารถศึกษารายละเอียดได้ที่ นโยบายความเป็นส่วนตัว และสามารถจัดการความเป็นส่วนตัวเองได้ของคุณได้เองโดยคลิกที่ ตั้งค่า

ตั้งค่าความเป็นส่วนตัว

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

ยอมรับทั้งหมด
จัดการความเป็นส่วนตัว
  • คุกกี้ที่จำเป็น
    เปิดใช้งานตลอด

    ประเภทของคุกกี้มีความจำเป็นสำหรับการทำงานของเว็บไซต์ เพื่อให้คุณสามารถใช้ได้อย่างเป็นปกติ และเข้าชมเว็บไซต์ คุณไม่สามารถปิดการทำงานของคุกกี้นี้ในระบบเว็บไซต์ของเราได้
    รายละเอียดคุกกี้

  • คุกกี้สำหรับการติดตามทางการตลาด

    ประเภทของคุกกี้ที่มีความจำเป็นในการใช้งานเพื่อการวิเคราะห์ และ นำเสนอโปรโมชัน สินค้า รวมถึงหลักสูตรฟรี และ สิทธิพิเศษต่าง ๆ คุณสามารถเลือกปิดคุกกี้ประเภทนี้ได้โดยไม่ส่งผลต่อการทำงานหลัก เว้นแต่การนำเสนอโปรโมชันที่อาจไม่ตรงกับความต้องการ
    รายละเอียดคุกกี้

บันทึกการตั้งค่า