ในบทความก่อนหน้านี้ในชุดนี้ เราได้พูดคุยกันอย่างกว้างขวางเกี่ยวกับ Gonet/http แพ็คเกจและวิธีการใช้สำหรับเว็บแอปพลิเคชันที่พร้อมสำหรับการผลิต เราเน้นที่ด้านการกำหนดเส้นทางและลักษณะเฉพาะอื่นๆ ของhttp.ServeMuxเป็นส่วนใหญ่ ชนิด
บทความนี้จะปิดการสนทนาใน ServeMux โดยการสาธิตวิธีใช้งานฟังก์ชันมิดเดิลแวร์กับเราเตอร์เริ่มต้นและแนะนำแพ็คเกจไลบรารีมาตรฐานอื่นๆ ที่แน่ใจว่าจะมีประโยชน์เมื่อพัฒนาบริการเว็บด้วย Go
มิดเดิลแวร์ใน Go
วิธีปฏิบัติในการตั้งค่าฟังก์ชันที่ใช้ร่วมกันซึ่งต้องเรียกใช้สำหรับคำขอ HTTP แบบปากเปล่าจำนวนมากเรียกว่า มิดเดิลแวร์ . การดำเนินการบางอย่าง เช่น การตรวจสอบสิทธิ์ การบันทึก และการตรวจสอบคุกกี้ มักถูกนำไปใช้เป็นฟังก์ชันมิดเดิลแวร์ ซึ่งดำเนินการตามคำขออย่างเป็นอิสระก่อนหรือหลังตัวจัดการเส้นทางปกติ
ในการใช้งานมิดเดิลแวร์ใน Go คุณต้องแน่ใจว่าคุณมีประเภทที่ตรงกับอินเทอร์เฟซ http.Handler โดยปกติหมายความว่าคุณต้องแนบเมธอดที่มีลายเซ็นServeHTTP(http.ResponseWriter, *http.Request) กับประเภท เมื่อใช้เมธอดนี้ ทุกประเภทจะตอบสนอง http.Handler อินเทอร์เฟซ
นี่เป็นตัวอย่างง่ายๆ:
package main
import "net/http"
type helloHandler struct {
name string
}
func (h helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello " + h.name))
}
func main() {
mux := http.NewServeMux()
helloJohn := helloHandler{name: "John"}
mux.Handle("/john", helloJohn)
http.ListenAndServe(":8080", mux)
}
คำขอใด ๆ ที่ส่งไปยัง /john เส้นทางจะถูกส่งตรงไปยังhelloHandler.ServeHTTP กระบวนการ. คุณสามารถสังเกตการทำงานนี้ได้โดยเริ่มต้นเซิร์ฟเวอร์และไปที่ http://localhost:8080/john
ต้องเพิ่ม ServeHTTP เมธอดเป็นประเภทกำหนดเองทุกครั้งที่คุณต้องการปรับใช้ http.Handler จะค่อนข้างน่าเบื่อ ดังนั้น net/http packageprovides http.HandlerFunc ซึ่งอนุญาตให้ใช้ฟังก์ชันทั่วไปเป็นตัวจัดการ HTTP
สิ่งที่คุณต้องทำคือตรวจสอบให้แน่ใจว่าฟังก์ชันของคุณมีลายเซ็นต่อไปนี้:func(http.ResponseWriter, *http.Request); จากนั้นแปลงเป็น http.HandlerFunc ชนิด
package main
import "net/http"
func helloJohnHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello John"))
}
func main() {
mux := http.NewServeMux()
mux.Handle("/john", http.HandlerFunc(helloJohnHandler))
http.ListenAndServe(":8080", mux)
}
คุณยังสามารถแทนที่ mux.Handle บรรทัดใน main ฟังก์ชั่นด้านบนด้วยmux.HandleFunc และส่งฟังก์ชันไปที่มันโดยตรง เราใช้รูปแบบนี้โดยเฉพาะในบทความที่แล้ว
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/john", helloJohnHandler)
http.ListenAndServe(":8080", mux)
}
ณ จุดนี้ ชื่อถูกฮาร์ดโค้ดลงในสตริง ไม่เหมือนเมื่อก่อนเมื่อเราตั้งชื่อใน main ก่อนเรียกตัวจัดการ หากต้องการลบข้อจำกัดนี้ เราสามารถปิดตรรกะของตัวจัดการได้ดังที่แสดงด้านล่าง:
package main
import "net/http"
func helloHandler(name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello " + name))
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/john", helloHandler("John"))
http.ListenAndServe(":8080", mux)
}
helloHandler ฟังก์ชันเองไม่เป็นไปตาม http.Handler ส่วนต่อประสาน แต่สร้างและส่งคืนฟังก์ชันที่ไม่ระบุชื่อที่ทำ ฟังก์ชันนี้ปิดทับ name พารามิเตอร์ ซึ่งหมายความว่าสามารถเข้าถึงได้เมื่อถูกเรียก ณ จุดนี้ helloHandler สามารถใช้ซ้ำได้หลายชื่อตามความจำเป็น
ทั้งหมดนี้เกี่ยวข้องกับมิดเดิลแวร์อย่างไร การสร้างฟังก์ชันมิดเดิลแวร์ทำได้ในลักษณะเดียวกับที่เราได้เห็นด้านบน แทนที่จะส่งสตริงไปยังส่วนปิด (ดังในตัวอย่าง) เราสามารถส่งตัวจัดการถัดไปในสายโซ่เป็นอาร์กิวเมนต์ได้
นี่คือรูปแบบที่สมบูรณ์:
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Middleware logic goes here...
next.ServeHTTP(w, r)
})
}
middleware ฟังก์ชันด้านบนยอมรับตัวจัดการและส่งคืนตัวจัดการ โปรดสังเกตว่าเราสามารถทำให้ฟังก์ชันที่ไม่ระบุตัวตนตอบสนอง http.Handler ได้อย่างไร โดยการแคสต์ไปที่ http.HandlerFunc พิมพ์. เมื่อสิ้นสุดฟังก์ชันนิรนาม การควบคุมจะถูกโอนไปยัง next ตัวจัดการโดยเรียกใช้ServeHTTP() กระบวนการ. หากคุณต้องการส่งค่าระหว่างตัวจัดการ เช่น ID ของผู้ใช้ที่ตรวจสอบสิทธิ์ คุณสามารถใช้ http.Request.Context() วิธีการแนะนำใน Go 1.7
มาเขียนฟังก์ชันมิดเดิลแวร์ที่แสดงให้เห็นรูปแบบนี้ง่ายๆ กัน ฟังก์ชันนี้เพิ่มคุณสมบัติที่เรียกว่า requestTime ไปยังออบเจกต์คำขอซึ่งใช้โดย helloHandler เพื่อแสดงการประทับเวลาของคำขอ
package main
import (
"context"
"net/http"
"time"
)
func requestTime(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ctx = context.WithValue(ctx, "requestTime", time.Now().Format(time.RFC3339))
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
func helloHandler(name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
responseText := "<h1>Hello " + name + "</h1>"
if requestTime := r.Context().Value("requestTime"); requestTime != nil {
if str, ok := requestTime.(string); ok {
responseText = responseText + "\n<small>Generated at: " + str + "</small>"
}
}
w.Write([]byte(responseText))
})
}
func main() {
mux := http.NewServeMux()
mux.Handle("/john", requestTime(helloHandler("John")))
http.ListenAndServe(":8080", mux)
}

เนื่องจากฟังก์ชันมิดเดิลแวร์ของเรายอมรับและส่งกลับ http.Handler พิมพ์ มันเป็นไปได้ที่จะสร้างห่วงโซ่ที่ไม่มีที่สิ้นสุดของฟังก์ชันมิดเดิลแวร์ที่ซ้อนกันอยู่ภายในกันและกัน
ตัวอย่างเช่น
mux := http.NewServeMux()
mux.Handle("/", middleware1(middleware2(appHandler)))
คุณสามารถใช้ห้องสมุดเช่น Alice เพื่อแปลงโครงสร้างด้านบนให้อยู่ในรูปแบบที่อ่านง่ายยิ่งขึ้น เช่น:
alice.New(middleware1, middleware2).Then(appHandler)
เทมเพลต
แม้ว่าการใช้เทมเพลตจะลดลงเมื่อมีแอปพลิเคชันหน้าเดียว แต่ยังคงเป็นส่วนสำคัญของโซลูชันการพัฒนาเว็บที่สมบูรณ์
Go มีแพ็คเกจสองชุดสำหรับทุกความต้องการในการสร้างแม่แบบของคุณ:text/template และhtml/template . ทั้งคู่มีอินเทอร์เฟซเดียวกัน แต่ส่วนหลังจะทำการเข้ารหัสลับเบื้องหลังเพื่อป้องกันการเจาะระบบโค้ดปลอม
แม้ว่าเทมเพลต Go จะไม่ได้สื่อถึงความรู้สึกได้มากที่สุด แต่ก็สามารถทำงานให้เสร็จลุล่วงได้ดีและสามารถใช้สำหรับแอปพลิเคชันที่ใช้งานจริงได้ อันที่จริงแล้ว Hugo ซึ่งเป็นเครื่องมือสร้างไซต์แบบสแตติกยอดนิยมนั้นใช้ระบบการสร้างเทมเพลตเป็นหลัก
เรามาดูกันว่า html/template . เป็นอย่างไร แพ็กเกจอาจใช้เพื่อส่งเอาต์พุต HTML เพื่อตอบสนองต่อคำขอของเว็บ
การสร้างเทมเพลต
สร้าง index.html ไฟล์ในไดเร็กทอรีเดียวกับ main.go . ของคุณ file และเพิ่มรหัสต่อไปนี้ลงในไฟล์:
<ul>
{{ range .TodoItems }}
<li>{{ . }}</li>
{{ end }}
</ul>
ถัดไป เพิ่มรหัสต่อไปนี้ใน main.go . ของคุณ ไฟล์:
package main
import (
"html/template"
"log"
"os"
)
func main() {
t, err := template.ParseFiles("index.html")
if err != nil {
log.Fatal(err)
}
todos := []string{"Watch TV", "Do homework", "Play games", "Read"}
err = t.Execute(os.Stdout, todos)
if err != nil {
log.Fatal(err)
}
}
หากคุณรันโปรแกรมด้านบนด้วย go run main.go . คุณควรเห็นผลลัพธ์ต่อไปนี้:
<ul>
<li>Watch TV</li>
<li>Do homework</li>
<li>Play games</li>
<li>Read</li>
</ul>
ยินดีด้วย! คุณเพิ่งสร้างเทมเพลต Go แรกของคุณ นี่คือคำอธิบายสั้น ๆ ของไวยากรณ์ที่เราใช้ในไฟล์เทมเพลต:
- Go ใช้วงเล็บปีกกาคู่ (
{{และ}}) เพื่อกำหนดขอบเขตการประเมินข้อมูลและโครงสร้างการควบคุม (เรียกว่า การกระทำ ) ในเทมเพลต - ช่วง
rangeการกระทำคือวิธีที่เราสามารถทำซ้ำโครงสร้างข้อมูล เช่น สไลซ์ .แสดงถึงบริบทปัจจุบัน ในrangeการกระทำ บริบทปัจจุบันคือส่วนของtodos. ภายในบล็อก{{ . }}หมายถึงแต่ละองค์ประกอบในสไลซ์
ใน main.go ไฟล์ template.ParseFiles เมธอดใช้ในการสร้างเทมเพลตใหม่จากไฟล์ตั้งแต่หนึ่งไฟล์ขึ้นไป เทมเพลตนี้จะดำเนินการในภายหลังโดยใช้ template.Execute กระบวนการ; ต้องใช้ io.Writer และข้อมูลที่จะนำไปใช้กับเทมเพลต
ในตัวอย่างข้างต้น เทมเพลตถูกเรียกใช้งานไปยังเอาต์พุตมาตรฐาน แต่เราสามารถรันไปยังปลายทางใดก็ได้ ตราบใดที่ตรงตาม io.Writer อินเตอร์เฟซ. ตัวอย่างเช่น หากคุณต้องการส่งคืนผลลัพธ์โดยเป็นส่วนหนึ่งของคำขอเว็บ สิ่งที่คุณต้องทำคือเรียกใช้เทมเพลตไปยัง ResponseWriter อินเทอร์เฟซดังที่แสดงด้านล่าง
package main
import (
"html/template"
"log"
"net/http"
)
func main() {
t, err := template.ParseFiles("index.html")
if err != nil {
log.Fatal(err)
}
todos := []string{"Watch TV", "Do homework", "Play games", "Read"}
http.HandleFunc("/todos", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
err = t.Execute(w, todos)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
http.ListenAndServe(":8080", nil)
}

ส่วนนี้มีขึ้นเพื่อเป็นการแนะนำสั้นๆ เกี่ยวกับแพ็คเกจเทมเพลตของ Go อย่าลืมตรวจสอบเอกสารประกอบสำหรับข้อความ/เทมเพลต และhtml/เทมเพลต หากคุณสนใจกรณีการใช้งานที่ซับซ้อนมากขึ้น
หากคุณไม่ได้ชื่นชอบวิธีการสร้างเทมเพลตของ Go คุณจะมีตัวเลือกอื่น เช่น ห้องสมุด Plush
การทำงานกับ JSON
หากคุณต้องการทำงานกับออบเจ็กต์ JSON คุณจะยินดีที่ทราบว่าไลบรารีมาตรฐานของ Go มีทุกสิ่งที่จำเป็นในการแยกวิเคราะห์และเข้ารหัส JSON ผ่าน encoding/json แพ็คเกจ
ประเภทเริ่มต้น
เมื่อเข้ารหัสหรือถอดรหัสวัตถุ JSON ใน Go จะมีการใช้ประเภทต่อไปนี้:
boolสำหรับบูลีน JSONfloat64สำหรับหมายเลข JSONstringสำหรับสตริง JSONnilสำหรับ JSON เป็นโมฆะmap[string]interface{}สำหรับวัตถุ JSON และ[]interface{}สำหรับอาร์เรย์ JSON
การเข้ารหัส
ในการเข้ารหัสโครงสร้างข้อมูลเป็น JSON json.Marshal มีการใช้ฟังก์ชัน นี่คือตัวอย่าง:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string
LastName string
Age int
email string
}
func main() {
p := Person{
FirstName: "Abraham",
LastName: "Freeman",
Age: 100,
email: "abraham.freeman@hey.com",
}
json, err := json.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(json))
}
ในโปรแกรมด้านบนนี้ เรามี Person struct มีสี่ฟิลด์ที่แตกต่างกัน ใน main ฟังก์ชัน ตัวอย่าง Person ถูกสร้างขึ้นด้วยฟิลด์ทั้งหมดเริ่มต้น json.Marshal จะใช้เมธอดเพื่อแปลง p โครงสร้างเป็น JSON เมธอดนี้ส่งคืนส่วนของไบต์หรือข้อผิดพลาด ซึ่งเราต้องจัดการก่อนเข้าถึงข้อมูล JSON
ในการแปลงส่วนของไบต์เป็นสตริงใน Go เราจำเป็นต้องทำการแปลงประเภทดังที่แสดงไว้ด้านบน การรันโปรแกรมนี้จะสร้างผลลัพธ์ดังต่อไปนี้:
{"FirstName":"Abraham","LastName":"Freeman","Age":100}
อย่างที่คุณเห็น เราได้รับอ็อบเจ็กต์ JSON ที่ถูกต้องซึ่งสามารถใช้ได้ในทุกวิถีทาง โปรดทราบว่า email ฟิลด์ถูกปล่อยออกจากผลลัพธ์ นี่เป็นเพราะไม่ได้ส่งออกจาก Person วัตถุโดยอาศัยการขึ้นต้นด้วยตัวพิมพ์เล็ก
โดยค่าเริ่มต้น Go จะใช้ชื่อคุณสมบัติเดียวกันใน struct เป็นชื่อฟิลด์ในวัตถุ JSON นั้น อย่างไรก็ตาม สิ่งนี้สามารถเปลี่ยนแปลงได้โดยใช้แท็ก structfield
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Age int `json:"age"`
email string `json:"email"`
}
แท็กฟิลด์ struct ด้านบนระบุว่าตัวเข้ารหัส JSON ควรจับคู่ FirstName คุณสมบัติใน struct เป็น first_name ฟิลด์ในวัตถุ JSON เป็นต้น การเปลี่ยนแปลงในตัวอย่างก่อนหน้านี้ทำให้เกิดผลลัพธ์ดังต่อไปนี้:
{"first_name":"Abraham","last_name":"Freeman","age":100}
ถอดรหัส
json.Unmarshal ฟังก์ชั่นใช้สำหรับถอดรหัสวัตถุ JSON เป็น Gostruct โดยมีลายเซ็นดังต่อไปนี้:
func Unmarshal(data []byte, v interface{}) error
ยอมรับข้อมูล JSON หนึ่งส่วนและสถานที่สำหรับจัดเก็บข้อมูลที่ถอดรหัส หากถอดรหัสสำเร็จ ข้อผิดพลาดที่ส่งคืนจะเป็น nil .
สมมติว่าเรามีวัตถุ JSON ต่อไปนี้
json := "{"first_name":"John","last_name":"Smith","age":35, "place_of_birth": "London", gender:"male"}"
เราสามารถถอดรหัสเป็น Person struct ดังที่แสดงด้านล่าง:
func main() {
b := `{"first_name":"John","last_name":"Smith","age":35, "place_of_birth": "London", "gender":"male", "email": "john.smith@hmail.com"}`
var p Person
err := json.Unmarshal([]byte(b), &p)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", p)
}
และคุณจะได้ผลลัพธ์ดังต่อไปนี้:
{FirstName:John LastName:Smith Age:35 email:}
Unmarshal ถอดรหัสเฉพาะฟิลด์ที่พบในประเภทปลายทาง ในกรณีนี้ place_of_birth และ gender จะถูกละเว้นเนื่องจากไม่ได้จับคู่กับฟิลด์ struct ใดๆ ใน Person . ลักษณะการทำงานนี้สามารถใช้ประโยชน์เพื่อเลือกเฉพาะบางฟิลด์เฉพาะจากออบเจ็กต์ JSON ขนาดใหญ่ เช่นเคย ฟิลด์ที่ไม่ถูกเอ็กซ์พอร์ตในโครงสร้างปลายทางจะไม่ได้รับผลกระทบแม้ว่าจะมีฟิลด์ที่สอดคล้องกันในออบเจ็กต์ JSON ก็ตาม นั่นเป็นเหตุผลที่ email ยังคงเป็นสตริงว่างในผลลัพธ์แม้ว่าจะมีอยู่ในวัตถุ JSON
ฐานข้อมูล
database/sql แพ็คเกจมีอินเทอร์เฟซทั่วไปรอบฐานข้อมูล SQL (หรือเหมือน SQL) ต้องใช้ร่วมกับโปรแกรมควบคุมฐานข้อมูล เช่น รายการที่ระบุไว้ที่นี่ เมื่อนำเข้าไดรเวอร์ฐานข้อมูล คุณต้องนำหน้าด้วยเครื่องหมายขีดล่าง _ เพื่อเริ่มต้น
ตัวอย่างเช่น นี่คือวิธีใช้แพ็คเกจ MySQLdriver กับ database/sql :
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
ภายใต้ประทุน ไดรเวอร์จะลงทะเบียนตัวเองว่าพร้อมใช้งานสำหรับdatabase/sql แพ็คเกจ แต่จะไม่ถูกใช้โดยตรงในรหัสของเรา วิธีนี้ช่วยลดการพึ่งพาไดรเวอร์เฉพาะเพื่อให้สามารถสลับไปใช้ไดรเวอร์อื่นได้อย่างง่ายดายโดยใช้ความพยายามเพียงเล็กน้อย
การเปิดการเชื่อมต่อฐานข้อมูล
ในการเข้าถึงฐานข้อมูล คุณต้องสร้าง sql.DB วัตถุดังที่แสดงด้านล่าง:
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
if err != nil {
log.Fatal(err)
}
}
sql.Open วิธีการเตรียมฐานข้อมูลที่เป็นนามธรรมเพื่อใช้ในภายหลัง มันไม่ได้สร้างการเชื่อมต่อกับฐานข้อมูลหรือตรวจสอบพารามิเตอร์การเชื่อมต่อ หากคุณต้องการให้แน่ใจว่าฐานข้อมูลพร้อมใช้งานและสามารถเข้าถึงได้ทันที ให้ใช้ db.Ping() วิธีการ:
err = db.Ping()
if err != nil {
log.Fatal(err)
}
การปิดการเชื่อมต่อฐานข้อมูล
หากต้องการปิดการเชื่อมต่อฐานข้อมูล คุณสามารถใช้ db.Close() . โดยปกติคุณต้องการdefer การปิดฐานข้อมูลจนกว่าฟังก์ชันที่เปิดฐานข้อมูลการเชื่อมต่อจะสิ้นสุดลง โดยปกติแล้วจะเป็น main ฟังก์ชัน:
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
if err != nil {
log.Fatal(err)
}
defer db.Close()
}
sql.DB วัตถุถูกออกแบบมาให้มีอายุยืนยาว ดังนั้นคุณจึงไม่ควรเปิดและปิดบ่อยๆ หากคุณทำเช่นนั้น คุณอาจประสบปัญหา เช่น การใช้ซ้ำที่ไม่ดีและการแบ่งปันการเชื่อมต่อ การใช้ทรัพยากรเครือข่ายไม่เพียงพอ ความล้มเหลวเป็นระยะๆ ทางที่ดีควรส่ง sql.DB วิธีการหรือทำให้ใช้ได้ทั่วโลกและปิดเฉพาะเมื่อโปรแกรมเข้าถึงที่เก็บข้อมูลนั้นเสร็จแล้ว
กำลังดึงข้อมูลจากฐานข้อมูล
การสอบถามตารางสามารถทำได้ในสามขั้นตอน ขั้นแรก เรียก db.Query() . จากนั้นวนซ้ำในแถว สุดท้าย ใช้ rows.Scan() เพื่อแยกแต่ละแถวเป็นตัวแปรไม่คงที่ นี่คือตัวอย่าง:
var (
id int
name string
)
rows, err := db.Query("select id, name from users where id = ?", 1)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
log.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
หากการสืบค้นส่งคืนแถวเดียว คุณสามารถใช้ db.QueryRow เมธอดแทน db.Query และหลีกเลี่ยงโค้ดสำเร็จรูปที่มีความยาวบางส่วนในโค้ดก่อนหน้า:
var (
id int
name string
)
err = db.QueryRow("select id, name from users where id = ?", 1).Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
ฐานข้อมูล NoSQL
Go ยังรองรับฐานข้อมูล NoSQL เป็นอย่างดี เช่น Redis, MongoDB, Cassandra และอื่นๆ แต่ไม่มีอินเทอร์เฟซมาตรฐานสำหรับการทำงานกับพวกมัน คุณจะต้องพึ่งพาแพ็คเกจไดรเวอร์ทั้งหมดสำหรับฐานข้อมูลเฉพาะ ตัวอย่างบางส่วนอยู่ด้านล่าง
- https://github.com/go-redis/redis (ไดรเวอร์ Redis)
- https://github.com/mongodb/mongo-go-driver (ไดรเวอร์ MongoDB)
- https://github.com/gocql/gocql (ไดรเวอร์ Cassandra)
- https://github.com/Shopify/sarama (ไดรเวอร์ Apache Kafka)
สรุป
ในบทความนี้ เราได้พูดถึงประเด็นสำคัญบางประการในการสร้างเว็บแอปพลิเคชันด้วย Go ตอนนี้คุณควรจะสามารถเข้าใจได้ว่าทำไม Goprogrammers หลายคนจึงสาบานด้วยไลบรารีมาตรฐาน มีความครอบคลุมมากและจัดเตรียมเครื่องมือที่จำเป็นสำหรับบริการที่พร้อมสำหรับการผลิต
หากคุณต้องการคำชี้แจงเกี่ยวกับสิ่งที่เรากล่าวถึงที่นี่ โปรดส่งข้อความถึงฉันทาง Twitter ในบทความถัดไปและสุดท้ายในชุดนี้ เราจะพูดถึง go เครื่องมือและวิธีใช้เพื่อจัดการกับงานทั่วไปในระหว่างการพัฒนาด้วย Go
ขอบคุณสำหรับการอ่านและขอให้สนุกกับการเขียนโค้ด!