مسیریابی

نقشه‌برداری در چارچوب Go Fiber، برای اتصال آدرس‌های مختلف به توابع کنترلی، به منظور پشتیبانی از پردازش درخواست‌های HTTP می‌باشد. این به عنوان نقطه ورودی برای همه درخواست‌های چارچوب وب عمل می‌کند.

توابع کنترلگر مسیر

ثبت مسیرهایی که به روش‌های خاص HTTP متصل هستند.

توجه: در برخی چارچوب‌ها، توابع کنترلگر به عنوان کنترل‌کننده‌ها نیز شناخته می‌شوند که به طور کلی همان معنی را دارند - تعیین اینکه کدام تابع (متد) برای پردازش درخواست HTTP ورودی استفاده می‌شود.

امضای تابع:

// روش‌های HTTP
func (app *App) Get(path string, handlers ...Handler) Router
func (app *App) Head(path string, handlers ...Handler) Router
func (app *App) Post(path string, handlers ...Handler) Router
func (app *App) Put(path string, handlers ...Handler) Router
func (app *App) Delete(path string, handlers ...Handler) Router
func (app *App) Connect(path string, handlers ...Handler) Router
func (app *App) Options(path string, handlers ...Handler) Router
func (app *App) Trace(path string, handlers ...Handler) Router
func (app *App) Patch(path string, handlers ...Handler) Router

// از شما اجازه می‌دهد تا متدها را به عنوان مقادیر مشخص کنید
func (app *App) Add(method, path string, handlers ...Handler) Router

// همه مسیرها را برای همه روش‌های HTTP ثبت می‌کند
// مشابه app.Use ولی پیشوندی را نمی‌گذارد
func (app *App) All(path string, handlers ...Handler) Router

مثال:

// کنترلگر GET ساده
app.Get("/api/list", func(c *fiber.Ctx) error {
  return c.SendString("این یک درخواست GET است!")
})

// کنترلگر POST ساده
app.Post("/api/register", func(c *fiber.Ctx) error {
  return c.SendString("این یک درخواست POST است!")
})

استفاده برای بارگذاری middleware و سرقت‌گیرنده‌های URL استفاده می‌شود. این مسیرها تنها با شروع هر مسیر همخوانی دارند، به عنوان مثال /john با /john/doe, /johnnnnn, و غیره همخوانی می‌کند.

امضای تابع middleware سفارشی:

func (app *App) Use(args ...interface{}) Router

مثال:

// هر درخواستی را همسان می‌کند
app.Use(func(c *fiber.Ctx) error {
    return c.Next()
})

// درخواست‌هایی را همسان می‌کند که با /api شروع می‌شوند
app.Use("/api", func(c *fiber.Ctx) error {
    return c.Next()
})

// درخواست‌هایی را همسان می‌کند که با /api یا /home شروع می‌شوند (پیشوند‌های چندگانه را پشتیبانی می‌کند)
app.Use([]string{"/api", "/home"}, func(c *fiber.Ctx) error {
    return c.Next()
})

// چندین کنترلگر را اضافه می‌کند
app.Use("/api", func(c *fiber.Ctx) error {
  c.Set("X-Custom-Header", random.String(32))
  return c.Next()
}, func(c *fiber.Ctx) error {
  return c.Next()
})

مسیر

مسیر مسیر، همراه با متد درخواست، انتها‌نقاطی را که می‌توان به آنها دسترسی داشت، تعریف می‌کند. مسیر می‌تواند یک رشته یا الگوی رشته باشد.

مثال‌های مسیر‌های مبتنی بر رشته

// این مسیر به درخواست‌های مسیر روت، "/" همخوانی می‌کند:
app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("مسیر ریشه")
})

// این مسیر به درخواست‌های "/about" همخوانی می‌کند:
app.Get("/about", func(c *fiber.Ctx) error {
  return c.SendString("درباره")
})

// این مسیر به درخواست‌های "/random.txt" همخوانی می‌کند:
app.Get("/random.txt", func(c *fiber.Ctx) error {
  return c.SendString("تصادفی.txt")

مشابه چارچوب expressJs، ترتیب اعلام مسیرها اهمیت دارد. وقتی یک درخواست دریافت می‌شود، مسیرها به ترتیبی که اعلام شده‌اند بررسی می‌شوند.

لطفا توجه داشته باشید: اطمینان حاصل کنید که مسیرهایی که دارای پارامترهای متغیر هستند، پس از مسیرهای دارای بخش‌های ثابت نوشته شوند تا از همخوانی اشتباه این بخش‌های متغیر جلوگیری شود که می‌تواند به رفتار غیرمنتظره‌ای منجر شود.

پارامترهای مسیر

پارامترهای مسیر عناصر پویا در یک مسیر هستند و می‌توانند نامگذاری شده یا بخش‌های بدون نام باشند. این بخش‌ها برای گرفتن مقادیر در مکان‌های مشخص شده در URL استفاده می‌شوند. می‌توانید از تابع Params برای دریافت این مقادیر استفاده کنید. در این تابع، پارامتر تابع نام پارامتر مسیر در مسیر است، یا برای پارامترهای بدون نام، این کاراکترها (*, +) و تعداد آن‌ها است.

کاراکتر وایلدکارد (*) یا علامت + نشان دهنده پارامترهای گریدی هستند.

همچنین در مسیرها امکان استفاده از پارامترهای اختیاری وجود دارد. برای پارامترهای نامگذاری شده، این پارامترها توسط یک علامت سوال قابل اختیار می‌باشند، در حالی که علامت + اختیاری نیست، و می‌توانید از کاراکترهای وایلدکارد برای نمایش یک محدوده پارامتر اختیاری و گریدی استفاده کنید.

مثال تعریف مسیر با پارامترهای مسیر

// پارامترها
app.Get("/user/:name/books/:title", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s\n", c.Params("name"))
    fmt.Fprintf(c, "%s\n", c.Params("title"))
    return nil
})
// علامت + - گریدی - اختیاری نیست
app.Get("/user/+", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("+"))
})

// پارامتر اختیاری
app.Get("/user/:name?", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("name"))
})

// وایلدکارد - گریدی - اختیاری
app.Get("/user/*", func(c *fiber.Ctx) error {
    return c.SendString(c.Params("*"))
})

// مسیر این درخواست "/v1/some/resource/name:customVerb" را هم متناسب می‌کند چون کاراکترهای پارامتر داخل روت زده شده‌اند
app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error {
    return c.SendString("Hello, Community")
})

به اندازه‌ی کافی علامت‌های خط تیره (-) و نقطه (.) به صورت حرفی تفسیر می‌شوند، می‌توانید همراه با پارامترهای مسیر برای دستیابی به اهداف مفید استفاده کنید.

تمام کاراکترهای پارامتر ویژه نیز با استفاده از \ قابل اجتناب است و ارزش‌های آن‌ها نادیده گرفته می‌شود، پس اگر می‌خواهید از آن‌ها در مسیر استفاده کنید. معمولاً استفاده از علامت برگ‌برگ توصیه می‌شود، زیرا که در مستندات عبارات منظم Go همیشه برای اطمینان از عدم ابهام استفاده می‌شوند و کاراکترهای فرار به‌طور تصادفی الگوی عبارت منظم را تحت تأثیر نمی‌گذارند.

// http://localhost:3000/plantae/prunus.persica
app.Get("/plantae/:genus.:species", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s.%s\n", c.Params("genus"), c.Params("species"))
    return nil // prunus.persica
})
// http://localhost:3000/flights/LAX-SFO
app.Get("/flights/:from-:to", func(c *fiber.Ctx) error {
    fmt.Fprintf(c, "%s-%s\n", c.Params("from"), c.Params("to"))
    return nil // LAX-SFO
})

همچنین، مسیرها می‌توانند از چندین پارامتر و چندین کاراکتر پارامتر بدون نام به طور متوالی استفاده کنند، مانند کاراکترهای وایلدکارد یا پلاس، که امکانات کاربران را داخل مسیرها به طور چشم‌گیری گسترش می‌دهد.

// GET /@v1
// Params: "sign" -> "@", "param" -> "v1"
app.Get("/:sign:param", handler)

// GET /api-v1
// Params: "name" -> "v1" 
app.Get("/api-:name", handler)

// GET /customer/v1/cart/proxy
// Params: "*1" -> "customer/", "*2" -> "/cart"
app.Get("/*v1*/proxy", handler)

// GET /v1/brand/4/shop/blue/xs
// Params: "*1" -> "brand/4", "*2" -> "blue/xs"
app.Get("/v1/*/shop/*", handler)

ما قبلاً مسیردهی را به مسیردهی Express سازگار کرده‌ایم، اما هنوز از عبارات منظم پشتیبانی نمی‌کند چرا که نسبت به‌ سایر موارد نسبتاً کند است.

محدودیت‌ها

هنگامی که یک تطابق با URL ورودی ایجاد می‌شود و مسیر URL از طریق پارامترها به مقادیر مسیر تقسیم می‌شود، محدودیت‌ها اجرا خواهند شد. این قابلیت در ورژن v2.37.0 معرفی شده و از .NET Core الهام گرفته شده است.

محدودیت‌ها برای اعتبارسنجی پارامترها نیستند. اگر محدودیت برای مقدار پارامتر نامعتبر باشد، Fiber یک دستیابی 404 بازگردان خواهد داد.

محدودیت مثال مثال‌های تطابق
int :id 123456789، -123456789
bool :active true، false
guid :id CD2C1638-1638-72D5-1638-DEADBEEF1638
float :weight 1.234، -1,001.01e8
minLen(value) :username<minLen(4)> test (حداقل 4 کاراکتر)
maxLen(value) :filename<maxLen(8)> MyFile (حداکثر 8 کاراکتر)
len(length) :filename<len(12)> somefile.txt (12 کاراکتر)
min(value) :age<min(18)> 19 (مقدار صحیح باید حداقل 18 باشد)
max(value) :age<max(120)> 91 (مقدار صحیح نمی‌تواند از 120 بیشتر شود)
range(min,max) :age<range(18,120)> 91 (مقدار صحیح باید حداقل 18 باشد اما نمی‌تواند از 120 بیشتر شود)
alpha :name Rick (رشته باید از یک یا چند کاراکتر الفبایی تشکیل شده باشد، بدون توجه به حالت حروف، a-z)
datetime :dob<datetime(2006\\-01\\-02)> 2005-11-01
regex(expression) :date<regex(\d{4}-\d{2}-\d{2})> 2022-08-27 (باید با عبارت منظم تطابق داشته باشد)

مثال‌ها

  • محدودیت تک‌مقداری
  • محدودیت‌های چندگانه
  • محدودیت با عبارت منظم
app.Get("/:test", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})

// curl -X GET http://localhost:3000/12 // 12

// curl -X GET http://localhost:3000/1 // نتوانست GET /1 را پیدا کند


می‌توانید با استفاده از `;` برای افزودن محدودیت‌های چندگانه استفاده کنید.

app.Get("/:test", func(c *fiber.Ctx) error { return c.SendString(c.Params("test")) })

// curl -X GET http://localhost:3000/120000 // نتوانست GET /120000 را پیدا کند

// curl -X GET http://localhost:3000/1 // نتوانست GET /1 را پیدا کند

// curl -X GET http://localhost:3000/250 // 250


Fiber محدودیت‌های عبارت منظم را هنگام ثبت مسیرها قبل از زمان کامپایل می‌کند، بنابراین برای محدودیت‌های عبارت منظم هیچ گونه هزینه عملکردی وجود ندارد.

```go
app.Get(`/:date`, func(c *fiber.Ctx) error {
  return c.SendString(c.Params("date"))
})

// curl -X GET http://localhost:3000/125 // نتوانست GET /125 را پیدا کند

// curl -X GET http://localhost:3000/test // نتوانست GET /test را پیدا کند

// curl -X GET http://localhost:3000/2022-08-27 // 2022-08-27


> هنگام استفاده از محدودیت‌های تاریخ‌زمان (`*`,`+`,`?`,`:`,`/`,``,``,`>`,';`,`(`,`)`)، برای جلوگیری از اشتباه در تفسیر، قبل از استفاده از کاراکترهای ویژه در مسیر از `\\` استفاده کنید.

**مثال پارامتر اختیاری**

همچنین می‌توانید محدودیت‌ها را به پارامترهای اختیاری اضافه کنید.

```go
app.Get("/:test?", func(c *fiber.Ctx) error {
  return c.SendString(c.Params("test"))
})
// curl -X GET http://localhost:3000/42
// 42
// curl -X GET http://localhost:3000/
//
// curl -X GET http://localhost:3000/7.0
// نتوانست GET /7.0 را پیدا کند

میان‌افزار

توابعی که برای تغییر درخواست‌ها یا پاسخ‌ها طراحی شده‌اند، به توابع میان‌افزار معروفند. Next یک تابع مسیریابی Fiber است که هنگام فراخوانی، تابع next را که با مسیر فعلی تطابق دارد، اجرا می‌کند.

نمونه تابع میان‌افزار

app.Use(func(c *fiber.Ctx) error {
  // تنظیم یک هدر سفارشی برای تمام پاسخ‌ها:
  c.Set("X-Custom-Header", "Hello, world")

  // ادامه به میان‌افزار بعدی:
  return c.Next()
})

app.Get("/", func(c *fiber.Ctx) error {
  return c.SendString("Hello, world!")
})

مسیر برای روش Use می‌تواند یک مسیر نصب‌شده یا مسیر پیشوندی باشد و باعث محدود شدن توابع میان‌افزار به درخواست‌هایی با مسیرهایی که با آن مسیر شروع می‌شود، می‌شود.

افزودن محدودیت‌های مسیر در زمان اجرا

به دلیل مشاوره‌های طراحی و عملکردی، افزودن دینامیک مسیرها پس از راه‌اندازی برنامه پشتیبانی نمی‌شود. لطفاً اطمینان حاصل کنید که تمامی مسیرها قبل از راه‌اندازی برنامه تعریف شده‌اند.

گروه‌بندی

اگر شما تعداد زیادی نقاط پایانی دارید، می‌توانید از Group برای سازماندهی مسیرها استفاده کنید.

func main() {
  app := fiber.New()

  api := app.Group("/api", middleware) // /api

  v1 := api.Group("/v1", middleware)   // /api/v1
  v1.Get("/list", handler)             // /api/v1/list
  v1.Get("/user", handler)             // /api/v1/user

  v2 := api.Group("/v2", middleware)   // /api/v2
  v2.Get("/list", handler)             // /api/v2/list
  v2.Get("/user", handler)             // /api/v2/user

  log.Fatal(app.Listen(":3000"))
}