Поскольку раньше я всегда был программистом на Java, на самом деле все полагаются на фреймворк в веб-разработке на Java, поэтому, когда я изучал Golang, я подумал о том, чтобы отказаться от фреймворка в разработке на Go и самому создать фреймворк для практики. Учась учиться на идеях Java и исходном коде некоторых фреймворков, он реализован на golang, чтобы одновременно достичь цели изучения Java и Golang, что очень красиво. Дизайн http в Golang очень легкий и хорошо масштабируемый.Новички могут легко создавать собственные функции маршрутизации, которые очень просты в использовании (здесь... Давайте поговорим о сервлетах Java, хотя я также прав, Java очень любит), см. демо ниже.
func HelloServer1(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w,"hello world")
}
func main() {
http.HandleFunc("/test", HelloServer1)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err.Error())
}
}
скопировать код
Всего несколькими строками кода вы можете успешно зарегистрировать интерфейс и запустить службу. Однако функции, предоставляемые собственным методом разработки, относительно упрощены.В настоящее время почти все реализации маршрутизации веб-приложений основаны на маршрутизаторе по умолчанию http, но маршрутизатор, поставляемый с Go, имеет несколько ограничений:
- Установка параметров не поддерживается, например, сопоставление универсального типа, например /user/:uid.
- Режим REST плохо поддерживается, и методы доступа не могут быть ограничены.Например, в приведенном выше примере пользователи, обращающиеся к /foo, могут использовать GET, POST, DELETE, HEAD и т. д. для доступа.
- Слишком много правил роутинга для общих сайтов, и писать их громоздко, можно упростить методом struct.
Go имеет такое ограничение, которое связано с методом по умолчанию, предоставляемым http.Давайте сначала рассмотрим две ключевые структуры http.
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool
h Handler
pattern string
}
скопировать код
Нам нужно сосредоточиться на двух ключевых местах, одно из них — это параметр m в ServeMux, его тип —map[string]muxEntry, тут естественно можно подумать, что параметр m отвечает за раздачу маршрутизации. Второй фокус — это muxEntry, muxEntry’sh Handler
Соответствующий интерфейс — это интерфейс, который мы написали, и вокруг этого интерфейса у http не так много других функций, даже нет единого стандарта веб-разработки, как в Java. Таким образом, http предоставляет только самые основные функции, и пользователям необходимо использовать эти функции в качестве основы, а затем YY может придумать структуру или более богатые функции, которые они хотят.
Прежде всего, мы можем быстро и легко установить метод Http, чтобы в будущем поддерживать спецификацию URL RESTFUL. Есть два простых способа, первый способИспользование 2D-карты,Прямо сейчасmap[string]map[string]http.HandlerFunc
, в котором одномерный ключ String представляет метод запроса, такой как post, get и т. д. Двумерная ключевая строка представляет URL-адрес, который необходимо сопоставить.Конечно, http.HandlerFunc — это особый метод обработки URL-запросов. Второй метод — это метод, принятый автором, фактически являющийся развитием первого метода.
Тип метода фиксирован, фактически мы можем использовать массив, а значение равноmap[string]http.HandlerFunc
реализовать.
const (
GET = iota
POST
PUT
DELETE
CONNECTIBNG
HEAD
OPTIONS
PATCH
TRACE
)
скопировать код
Ознакомившись с настройками вышеперечисленных констант, читатель уже должен знать, что я имею в виду,например: массив [0] представляет собой набор всех интерфейсов в рамках метода GET, а массив [1] представляет набор всех интерфейсов в рамках метода POST.Основной принцип на самом деле прост: все интерфейсы в методе Get сохраняются в значении array[0] для вывода других методов. Принцип прост, но дизайн фреймворка должен иметь высокую связность и низкую связанность.Распределение маршрутов в веб-фреймворке является основой, и на этом необходимо построить дополнительные функции, такие как фильтры. В начальном дизайне должна быть гарантирована масштабируемость, поэтому я думаю, что сложность заключается в этом. Код находится непосредственно ниже, и соответствующий код полностью прокомментирован.
package odserver
import (
"net/http"
)
//实现IOdServer的接口,以及http提供ServeHttp方法
type OdServer struct {
router MethodMaps
}
type IOdServer interface {
GET(url string, f HandlerFunc)
POST(url string, f HandlerFunc)
PUT(url string, f HandlerFunc)
DELETE(url string, f HandlerFunc)
}
type HandlerMapped struct {
f HandlerFunc
}
//接口函数单位,即我们编写代码逻辑的函数
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
func Default() *OdServer {
return &OdServer{
router:NewRouter(),
}
}
//实现Handler接口,匹配方法以及路径
func (o *OdServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
//转发给doHandler进行执行
o.doHandler(w,req)
}
//判断需要执行的Http Method,从而查找对应的接口并且执行
func (o *OdServer) doHandler(w http.ResponseWriter, req *http.Request) {
switch req.Method {
case http.MethodGet:
{
if hm, ok := o.router.GetMapping(req.URL.RequestURI()); ok {
hm.f(w, req)
}
}
case http.MethodPost:
{
if hm, ok := o.router.PostMapping(req.URL.RequestURI()); ok {
hm.f(w, req)
}
}
case http.MethodDelete:
{
if hm, ok := o.router.DeleteMapping(req.URL.String()); ok {
hm.f(w, req)
}
}
case http.MethodPut:
{
if hm, ok := o.router.PutMapping(req.URL.String()); ok {
hm.f(w, req)
}
}
default:
{
}
}
}
func (o *OdServer) GET(url string, f HandlerFunc) {
o.router.GetAdd(url, HandlerMapped{f: f})
}
func (o *OdServer) POST(url string, f HandlerFunc) {
o.router.PostAdd(url, HandlerMapped{f: f})
}
func (o *OdServer) PUT(url string, f HandlerFunc) {
o.router.PutAdd(url, HandlerMapped{f: f})
}
func (o *OdServer) DELETE(url string, f HandlerFunc) {
o.router.DeleteAdd(url, HandlerMapped{f: f})
}
скопировать код
package odserver
/**
提供基本的路由功能,添加路由,查找路由
*/
const (
GET = iota
POST
PUT
DELETE
CONNECTIBNG
HEAD
OPTIONS
PATCH
TRACE
)
func NewRouter() MethodMaps {
return []handler{
GET: make(handler),
POST: make(handler),
PUT: make(handler),
DELETE: make(handler),
}
}
type MethodMaps [] handler
type handler map[string]HandlerMapped
//映射路由,获取Get方法下对应的接口
func (m MethodMaps) GetMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[GET][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,获取Post方法下对应的接口
func (m MethodMaps) PostMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[POST][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,获取Delete方法下对应的接口
func (m MethodMaps) DeleteMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[DELETE][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//映射路由,获取Put方法下对应的接口
func (m MethodMaps) PutMapping(url string) (HandlerMapped, bool) {
if hm, ok := m[PUT][url]; ok {
return hm, true
}
return HandlerMapped{}, false
}
//增加Get方法下的接口
func (m MethodMaps) GetAdd(url string, mapped HandlerMapped) {
if _, ok := m.GetMapping(url); ok {
panic("duplicate url with get method")
}
m[GET].SetUrl(url,mapped)
}
//增加Post方法下的接口
func (m MethodMaps) PostAdd(url string, mapped HandlerMapped) {
if _, ok := m.GetMapping(url); ok {
panic("duplicate url with Post method")
}
m[POST].SetUrl(url,mapped)
}
//增加Put方法下的接口
func (m MethodMaps) PutAdd(url string, mapped HandlerMapped) {
if _, ok := m.GetMapping(url); ok {
panic("duplicate url with Put method")
}
m[PUT].SetUrl(url,mapped)
}
//增加Delete方法下的接口
func (m MethodMaps) DeleteAdd(url string, mapped HandlerMapped) {
if _, ok := m.GetMapping(url); ok {
panic("duplicate url with Delete method")
}
m[DELETE].SetUrl(url,mapped)
}
func (h handler) SetUrl(url string, mapped HandlerMapped) {
h[url] = mapped
}
скопировать код
Как я уже сказал, я думаю, что более интересным для изучения Golang является то, что вы можете перенести то, что вы узнали из Java, и попытаться реализовать это в Golang, не только изучая Golang, но и улучшая свое понимание Java. Если у читателя есть лучший способ, пожалуйста, дайте мне знать
Ссылка: #Заметки об исследовании Golang — краткий анализ стандартной библиотеки «net/http» и самодельного простого фреймворка маршрутизации.