chi
هو جهاز توجيه خفيف الوزن ، ظهوره وقابل للتأليف لبناء خدمات HTTP. إنه جيد بشكل خاص في مساعدتك في كتابة خدمات API الكبيرة التي يمكن الحفاظ عليها مع نمو مشروعك وتغييره. تم تصميم chi
على حزمة context
الجديدة التي تم تقديمها في GO 1.7 للتعامل مع القيم الإشارات والإلغاء وقيم الطلب عبر سلسلة معالج.
كان تركيز المشروع هو البحث عن تصميم أنيق ومريح لكتابة خوادم API REST ، التي تم كتابتها أثناء تطوير خدمة API Pressly التي تعمل على تشغيل خدمة API العامة ، والتي بدورها تعمل على تشغيل جميع تطبيقات من جانب العميل.
الاعتبارات الرئيسية لتصميم CHI هي: بنية المشروع ، قابلية الصيانة ، معالجات HTTP القياسية (stdlib-only) ، إنتاجية المطورين ، وتفكيك نظام كبير في العديد من الأجزاء الصغيرة. جهاز التوجيه الأساسي github.com/go-chi/chi
صغير جدًا (أقل من 1000 LOC) ، لكننا قمنا أيضًا بتضمين بعض الحالات الفرعية المفيدة/الاختيارية: البرامج الوسيطة والعرض والثبات. نأمل أن تستمتع به أيضًا!
go get -u github.com/go-chi/chi/v5
net/http
context
جديدة ، وتوفير تسلسل القيمة ، والإلغاء والمهلاتdocgen
من مصدرك إلى JSON أو Markdownانظر _examples/ للحصول على مجموعة متنوعة من الأمثلة.
سهلة مثل:
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main () {
r := chi . NewRouter ()
r . Use ( middleware . Logger )
r . Get ( "/" , func ( w http. ResponseWriter , r * http. Request ) {
w . Write ([] byte ( "welcome" ))
})
http . ListenAndServe ( ":3000" , r )
}
معاينة الراحة:
فيما يلي معاينة صغيرة لما يبدو عليه التوجيه مع تشي. ألقِ نظرة أيضًا على مستندات التوجيه التي تم إنشاؤها في JSON (Routes.json) وفي Markdown (Routes.MD).
أوصي بشدة بقراءة مصدر الأمثلة المذكورة أعلاه ، وسوف تظهر لك جميع ميزات CHI وتكون بمثابة شكل جيد من الوثائق.
import (
//...
"context"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main () {
r := chi . NewRouter ()
// A good base middleware stack
r . Use ( middleware . RequestID )
r . Use ( middleware . RealIP )
r . Use ( middleware . Logger )
r . Use ( middleware . Recoverer )
// Set a timeout value on the request context (ctx), that will signal
// through ctx.Done() that the request has timed out and further
// processing should be stopped.
r . Use ( middleware . Timeout ( 60 * time . Second ))
r . Get ( "/" , func ( w http. ResponseWriter , r * http. Request ) {
w . Write ([] byte ( "hi" ))
})
// RESTy routes for "articles" resource
r . Route ( "/articles" , func ( r chi. Router ) {
r . With ( paginate ). Get ( "/" , listArticles ) // GET /articles
r . With ( paginate ). Get ( "/{month}-{day}-{year}" , listArticlesByDate ) // GET /articles/01-16-2017
r . Post ( "/" , createArticle ) // POST /articles
r . Get ( "/search" , searchArticles ) // GET /articles/search
// Regexp url parameters:
r . Get ( "/{articleSlug:[a-z-]+}" , getArticleBySlug ) // GET /articles/home-is-toronto
// Subrouters:
r . Route ( "/{articleID}" , func ( r chi. Router ) {
r . Use ( ArticleCtx )
r . Get ( "/" , getArticle ) // GET /articles/123
r . Put ( "/" , updateArticle ) // PUT /articles/123
r . Delete ( "/" , deleteArticle ) // DELETE /articles/123
})
})
// Mount the admin sub-router
r . Mount ( "/admin" , adminRouter ())
http . ListenAndServe ( ":3333" , r )
}
func ArticleCtx ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
articleID := chi . URLParam ( r , "articleID" )
article , err := dbGetArticle ( articleID )
if err != nil {
http . Error ( w , http . StatusText ( 404 ), 404 )
return
}
ctx := context . WithValue ( r . Context (), "article" , article )
next . ServeHTTP ( w , r . WithContext ( ctx ))
})
}
func getArticle ( w http. ResponseWriter , r * http. Request ) {
ctx := r . Context ()
article , ok := ctx . Value ( "article" ).( * Article )
if ! ok {
http . Error ( w , http . StatusText ( 422 ), 422 )
return
}
w . Write ([] byte ( fmt . Sprintf ( "title:%s" , article . Title )))
}
// A completely separate router for administrator routes
func adminRouter () http. Handler {
r := chi . NewRouter ()
r . Use ( AdminOnly )
r . Get ( "/" , adminIndex )
r . Get ( "/accounts" , adminListAccounts )
return r
}
func AdminOnly ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
ctx := r . Context ()
perm , ok := ctx . Value ( "acl.permission" ).( YourPermissionType )
if ! ok || ! perm . IsAdmin () {
http . Error ( w , http . StatusText ( 403 ), 403 )
return
}
next . ServeHTTP ( w , r )
})
}
يعتمد توجيه تشي على نوع من باتريشيا راديكس تري. جهاز التوجيه متوافق تمامًا مع net/http
.
بنيت على الجزء العلوي من الشجرة هي واجهة Router
:
// Router consisting of the core routing methods used by chi's Mux,
// using only the standard net/http.
type Router interface {
http. Handler
Routes
// Use appends one or more middlewares onto the Router stack.
Use ( middlewares ... func (http. Handler ) http. Handler )
// With adds inline middlewares for an endpoint handler.
With ( middlewares ... func (http. Handler ) http. Handler ) Router
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group ( fn func ( r Router )) Router
// Route mounts a sub-Router along a `pattern`` string.
Route ( pattern string , fn func ( r Router )) Router
// Mount attaches another http.Handler along ./pattern/*
Mount ( pattern string , h http. Handler )
// Handle and HandleFunc adds routes for `pattern` that matches
// all HTTP methods.
Handle ( pattern string , h http. Handler )
HandleFunc ( pattern string , h http. HandlerFunc )
// Method and MethodFunc adds routes for `pattern` that matches
// the `method` HTTP method.
Method ( method , pattern string , h http. Handler )
MethodFunc ( method , pattern string , h http. HandlerFunc )
// HTTP-method routing along `pattern`
Connect ( pattern string , h http. HandlerFunc )
Delete ( pattern string , h http. HandlerFunc )
Get ( pattern string , h http. HandlerFunc )
Head ( pattern string , h http. HandlerFunc )
Options ( pattern string , h http. HandlerFunc )
Patch ( pattern string , h http. HandlerFunc )
Post ( pattern string , h http. HandlerFunc )
Put ( pattern string , h http. HandlerFunc )
Trace ( pattern string , h http. HandlerFunc )
// NotFound defines a handler to respond whenever a route could
// not be found.
NotFound ( h http. HandlerFunc )
// MethodNotAllowed defines a handler to respond whenever a method is
// not allowed.
MethodNotAllowed ( h http. HandlerFunc )
}
// Routes interface adds two methods for router traversal, which is also
// used by the github.com/go-chi/docgen package to generate documentation for Routers.
type Routes interface {
// Routes returns the routing tree in an easily traversable structure.
Routes () [] Route
// Middlewares returns the list of middlewares in use by the router.
Middlewares () Middlewares
// Match searches the routing tree for a handler that matches
// the method/path - similar to routing a http request, but without
// executing the handler thereafter.
Match ( rctx * Context , method , path string ) bool
}
تقبل كل طريقة توجيه pattern
عنوان URL وسلسلة من handlers
. يدعم نمط عنوان URL المسمى params (أي /users/{userID}
) و wildcards (أي. /admin/*
). يمكن جلب معلمات URL في وقت التشغيل عن طريق الاتصال chi.URLParam(r, "userID")
للمعلمات المسماة و chi.URLParam(r, "*")
لمعلمة بطاقة Wildcard.
تشي الأوسط هي مجرد معالجات الوسيطة الشباك/HTTP. لا يوجد شيء مميز عنهم ، مما يعني أن جهاز التوجيه وجميع الأدوات مصممة لتكون متوافقة وودية مع أي برامج وسيطة في المجتمع. يوفر هذا قابلية أفضل بكثير وإعادة استخدام الحزم وهو في قلب الغرض من تشي.
فيما يلي مثال على برنامج Net/HTTP الوسيط القياسي حيث نقوم بتعيين مفتاح سياق "user"
قيمة "123"
. يعين هذا الوسيطة معرف المستخدم الافتراضي على سياق الطلب ويتصل بالمعالج التالي في السلسلة.
// HTTP middleware setting a value on the request context
func MyMiddleware ( next http. Handler ) http. Handler {
return http . HandlerFunc ( func ( w http. ResponseWriter , r * http. Request ) {
// create new context from `r` request context, and assign key `"user"`
// to value of `"123"`
ctx := context . WithValue ( r . Context (), "user" , "123" )
// call the next handler in the chain, passing the response writer and
// the updated request object with the new context value.
//
// note: context.Context values are nested, so any previously set
// values will be accessible as well, and the new `"user"` key
// will be accessible from this point forward.
next . ServeHTTP ( w , r . WithContext ( ctx ))
})
}
يستخدم CHI معالجات طلب Net/HTTP القياسية. هذا المقتطف الصغير هو مثال على http.handler func يقرأ معرف المستخدم من سياق الطلب - من الناحية الافتراضية ، وتحديد المستخدم الذي يرسل طلبًا مصادقًا ، تم التحقق من صحة+بواسطة معالج الوسيطة السابق.
// HTTP handler accessing data from the request context.
func MyRequestHandler ( w http. ResponseWriter , r * http. Request ) {
// here we read from the request context and fetch out `"user"` key set in
// the MyMiddleware example above.
user := r . Context (). Value ( "user" ).( string )
// respond to the client
w . Write ([] byte ( fmt . Sprintf ( "hi %s" , user )))
}
يقوم جهاز التوجيه التابع لـ Chi بتخزين معلمات عنوان URL لخزن مباشرة على سياق الطلب. فيما يلي مثال على كيفية الوصول إلى معاملات URL في معالجات NET/HTTP الخاصة بك. وبالطبع ، فإن الأوساط المتوسطة قادرة على الوصول إلى نفس المعلومات.
// HTTP handler accessing the url routing parameters.
func MyRequestHandler ( w http. ResponseWriter , r * http. Request ) {
// fetch the url parameter `"userID"` from the request of a matching
// routing pattern. An example routing pattern could be: /users/{userID}
userID := chi . URLParam ( r , "userID" )
// fetch `"key"` from the request context
ctx := r . Context ()
key := ctx . Value ( "key" ).( string )
// respond to the client
w . Write ([] byte ( fmt . Sprintf ( "hi %v, %v" , userID , key )))
}
يأتي CHI مزودًا بحزمة middleware
اختيارية ، مما يوفر مجموعة من الأوساط القياسية net/http
Middlewares. يرجى ملاحظة أنه يمكن استخدام أي برامج وسيطة في النظام الإيكولوجي المتوافق أيضًا مع net/http
مع Mux CHI.
معالج تشي/الوسيطة | وصف |
---|---|
lemtcontentencoding | يفرض رؤوس ترميز المحتوى من القائمة البيضاء |
lemtcontenttype | القائمة البيضاء الصريحة من أنواع المحتوى المقبولة |
Basicauth | مصادقة HTTP الأساسية |
ضغط | ضغط GZIP للعملاء الذين يقبلون الاستجابات المضغوطة |
ContentCharset | تأكد من رؤوس طلبات نوع المحتوى |
CleanPath | تنظيف مائل مزدوج من مسار الطلب |
جيثيد | توجيه طلبات الرأس غير المحددة تلقائيًا للحصول على معالجات |
نبض القلب | مراقبة نقطة النهاية للتحقق من نبض الخوادم |
المسجل | يسجل بداية ونهاية كل طلب مع وقت المعالجة المنقضي |
nocache | يضع رؤوس الاستجابة لمنع العملاء من التخزين المؤقت |
البروفيلر | قم بإرفاق NET/HTTP/PPROF بسهولة بسهولة |
Realip | يعين remoteaddr http.request إلى إما x-al-ip أو x-forward-for for |
المسترجع | تمتص الذعر برشاقة وتطبع تتبع المكدس |
طلب | حقن معرف الطلب في سياق كل طلب |
إعادة توجيه | إعادة توجيه مائلات على مسارات التوجيه |
RouteHeaders | معالجة الطريق لرؤوس الطلب |
سيثدير | برامج وسيطة قصيرة اليد لتعيين مفتاح/قيمة رأس استجابة |
شرائح الشقة | القطع المقطوعة على مسارات التوجيه |
غروب | غروب الشمس انخفاض رأس/غروب الشمس للاستجابة |
خنق | يضع السقف على عدد الطلبات المتزامنة |
نفذ الوقت | إشارات إلى سياق الطلب عند الوصول إلى الموعد النهائي المهلة |
urlformat | Extension من عنوان URL ووضعه عند سياق الطلب |
تقل القيمة | برامج وسيطة قصيرة اليد لتعيين مفتاح/قيمة في سياق الطلب |
يرجى الاطلاع على https://github.com/go-chi للحصول على حزم إضافية.
طَرد | وصف |
---|---|
كورس | مشاركة الموارد عبر الأصل (CORS) |
Docgen | طباعة طرق chi.router في وقت التشغيل |
jwtauth | مصادقة JWT |
Hostrouter | توجيه الطلب المستند إلى المجال/المضيف |
httplog | طلب HTTP صغير منظم صغير ولكنه قوي |
httprate | محدد معدل طلب HTTP |
httptracer | مكتبة تتبع الأداء HTTP طلب |
httpvcr | اكتب اختبارات حتمية للمصادر الخارجية |
تدافع | HTTP طلب coalescer |
context
هو PKG صغير يوفر واجهة بسيطة للإشارة سياق عبر مكدسات المكالمات والغرووتات. لقد كتبه في الأصل سمير أجاني وهو متاح في stdlib منذ Go1.7.
تعرف على المزيد في https://blog.golang.org/context
و..
الجناح المعياري: https://github.com/pkieltyka/go-http-routing-benchmark
النتائج اعتبارًا من 29 نوفمبر 2020 مع GO 1.15.5 على Linux AMD 3950X
BenchmarkChi_Param 3075895 384 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param5 2116603 566 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Param20 964117 1227 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParamWrite 2863413 420 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubStatic 3045488 395 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubParam 2204115 540 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GithubAll 10000 113811 ns/op 81203 B/op 406 allocs/op
BenchmarkChi_GPlusStatic 3337485 359 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusParam 2825853 423 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlus2Params 2471697 483 ns/op 400 B/op 2 allocs/op
BenchmarkChi_GPlusAll 194220 5950 ns/op 5200 B/op 26 allocs/op
BenchmarkChi_ParseStatic 3365324 356 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseParam 2976614 404 ns/op 400 B/op 2 allocs/op
BenchmarkChi_Parse2Params 2638084 439 ns/op 400 B/op 2 allocs/op
BenchmarkChi_ParseAll 109567 11295 ns/op 10400 B/op 52 allocs/op
BenchmarkChi_StaticAll 16846 71308 ns/op 62802 B/op 314 allocs/op
مقارنة مع أجهزة التوجيه الأخرى: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
ملاحظة: تخصيصات التخصيص في المعيار أعلاه من المكالمات إلى http.request's WithContext(context.Context)
التي تستنسخ http.request ، تضع Context()
على الطلب المكرر (المخصص) ويعيده إلى الطلب الجديد هدف. هذه هي الطريقة التي يعمل بها سياق إعداد طلب في GO.
سنكون أكثر من سعداء برؤية مساهماتك!
تشي هو مجرد جهاز توجيه HTTP يتيح لك تحلل الطلب مع العديد من الطبقات الأصغر. تستخدم العديد من الشركات CHI لكتابة خدمات REST لواجهة برمجة التطبيقات العامة الخاصة بها. ولكن ، يعد REST مجرد اتفاقية لإدارة الحالة عبر HTTP ، وهناك الكثير من القطع الأخرى المطلوبة لكتابة نظام خادم عميل كامل أو شبكة من الخدمات الصغيرة.
بالنظر إلى ما وراء الراحة ، أوصي أيضًا ببعض الأعمال الأحدث في هذا المجال:
حقوق الطبع والنشر (C) 2015-Peter Kieltyka الحاضر
مرخصة بموجب ترخيص معهد ماساتشوستس للتكنولوجيا