ساخت سرور وب سریع با زبان سلام: HTTP، مسیریابی، میان‌افزار، WebSocket و gRPC

هر آنچه کتابخانه‌ی استاندارد سلام برای سرویس‌های شبکه دارد، از سرور HTTP ده‌خطی تا اتاق‌های WebSocket و gRPC؛ اینکه سرور از درون چطور کار می‌کند، و بنچمارک مسیریاب چه چیزی را نشان می‌دهد و چه چیزی را نه.

در این مقاله
  1. کوچک‌ترین سرور HTTP با زبان سلام
  2. مسیریابی HTTP: پارامترها، گروه‌ها، ۴۰۴ و ۴۰۵
  3. API از نوع REST با میان‌افزار و احراز هویت
  4. سرور از درون چطور کار می‌کند و چقدر سریع است
  5. سرور WebSocket و اتاق‌های پخش همگانی
  6. gRPC و HTTP/2 در سلام
  7. salam serve: سرور وبی که با پیکربندی کار می‌کند
  8. محدودیت‌هایی که پیش از ساختن روی آن باید بدانید
  9. پرسش‌های پرتکرار

سرور وب در زبان برنامه‌نویسی سلام یک برنامه‌ی کامپایلی معمولی است که روی کتابخانه‌ی استاندارد ساخته می‌شود: net.http اتصال‌ها را می‌پذیرد و درخواست‌ها را تجزیه می‌کند، net.router بر اساس روش و مسیر رویدادگیر را انتخاب می‌کند، و بسته‌های همراه، میان‌افزار، نشست، اعتبارسنجی، WebSocket، HTTP/2 و gRPC را اضافه می‌کنند. مسیریاب و سرور HTTP سلام به یک فایل اجرایی بومی بدون زباله‌روب (Garbage Collector) و بدون وابستگی بیرونی کامپایل می‌شوند، و در بنچمارک منتشرشده‌ی پروژه، روی یک دستگاه، به درخواست‌های بیشتری در ثانیه پاسخ دادند تا کتابخانه‌ی استاندارد Go، Fiber، Express و سرور PHP. این بنچمارک ملاحظاتی دارد و این مقاله آن‌ها را هم کنار کد می‌آورد.

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

کوچک‌ترین سرور HTTP با زبان سلام

این یک سرور کامل است. به / با متن پاسخ می‌دهد، به /hello/:name با JSONی که از پارامتر مسیر ساخته می‌شود، و پوشه‌ای از پرونده‌های ایستا را زیر /assets ارائه می‌کند.

سلام
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.مسیریاب

تابع سلام کن(زمینه: صحیح۶۴):
    اچ تی تی پی.متن(زمینه، "درود از سلام")
پایان

تابع خوشامد(زمینه: صحیح۶۴):
    اچ تی تی پی.جیسون(زمینه، `{"hello":"` + اچ تی تی پی.پارامتر(زمینه، "name") + `"}`)
پایان

تابع ریشه:
    ناپایا م := مسیریاب.مسیریاب جدید()
    مسیریاب.دریافت(م، "/"، سلام کن)
    مسیریاب.دریافت(م، "/hello/:name"، خوشامد)
    مسیریاب.ایستا(م، "/assets"، "public")
    ناپایا س := اچ تی تی پی.سرور جدید(۸۰۸۰)
    اچ تی تی پی.فعال سازی گزارش دسترسی(س)
    اچ تی تی پی.استفاده(س، م)
    اچ تی تی پی.اجرا(س)
پایان

salam run server.salam آن را روشن می‌کند؛ salam build server.salam --output=server یک فایل اجرایی تنها می‌سازد که می‌توانید روی یک سرور لینوکس کپی و اجرا کنید. شکل رویدادگیر همه‌جا یکی است: تابعی که شناسه‌ی زمینه‌ی درخواست را می‌گیرد. درخواست با اچ تی تی پی.پارامتر، اچ تی تی پی.پرسمان، اچ تی تی پی.سرصفحه، اچ تی تی پی.فرم، اچ تی تی پی.بدنه و اچ تی تی پی.مقدار کوکی خوانده می‌شود و پاسخ با اچ تی تی پی.متن، اچ تی تی پی.جیسون، اچ تی تی پی.اچ تی ام ال، اچ تی تی پی.تنظیم وضعیت و اچ تی تی پی.تنظیم سرصفحه نوشته می‌شود. تا رویدادگیر برنگشته چیزی فرستاده نمی‌شود، پس وضعیت، سرآیندها و بدنه با هم می‌روند.

برای محیط عملیاتی، مرجع net.http تنظیم‌های بیشتر را نشان می‌دهد: تنظیم میزبان با "0.0.0.0" درون کانتینر، بیشینه بایت بدنه و بیشینه بایت سرایند برای رد کردن درخواست‌های بیش از اندازه، تنظیم بیکاری زنده نگه داشتن برای اتصال‌های بیکار، پنهان سازی توکن برای حذف نام سرور از پاسخ، و اجرای امن (http.RunTLS) با گواهی و کلید برای ارائه‌ی مستقیم HTTPS به جای قرار گرفتن پشت پراکسی.

مسیریابی HTTP: پارامترها، گروه‌ها، ۴۰۴ و ۴۰۵

مسیریاب net.router بر اساس روش و مسیر تطبیق می‌دهد، با پارامترهای :name و نویسه‌ی عام *. قاعده‌های اولویتش ثابت و مستندند، و این وقتی یک API چند ده مسیر پیدا می‌کند مهم‌تر از آن است که به نظر می‌رسد:

  • بخش لفظی بر پارامتر و پارامتر بر * برتری دارد، پس /users/me به رویدادگیر خودش می‌رسد حتی اگر /users/:name زودتر ثبت شده باشد.
  • میان دو مسیر عام، آنکه زودتر ثبت شده برنده است، پس مسیر همه‌گیر /* آخر ثبت می‌شود.
  • اسلش پایانی همچنان به مسیر پارامتردار می‌رسد و درخواست HEAD به مسیر GET برمی‌گردد.
  • مسیریاب.گروه(م، "/api/v1"، "GET"، "/items"، فهرست) مسیری را زیر یک پیشوند ثبت می‌کند؛ API‌های نسخه‌دار معمولاً همین‌طور چیده می‌شوند.

مسیریاب.اعزام (router.Dispatch) به شما اجازه می‌دهد بدون سرور از مسیریاب بپرسید چه خواهد کرد؛ صفحه‌ی مرجع با همین یک پاسخ درست 405 Method Not Allowed با سرآیند Allow می‌سازد، به جای یک ۴۰۴ گمراه‌کننده. مسیریاب.تنظیم مدیر پیش‌فرض رویدادگیری برای بقیه‌ی درخواست‌ها نصب می‌کند و مسیریاب.ایستا پوشه‌ای را کنار API ارائه می‌کند و پرونده‌ها را پس از نخستین درخواست در حافظه نگه می‌دارد.

یک قاعده از مرجع ارزش تکرار دارد: همه‌ی مسیرها را پیش از اچ تی تی پی.استفاده ثبت کنید، چون سرور یک رونوشت از مسیریاب نگه می‌دارد.

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

سلام زنجیره‌ی میان‌افزار ندارد و راهی هم برای پیچیدن یک رویدادگیر از بیرون نیست. میان‌افزار یک تابع معمولی است که در نخستین خط‌های رویدادگیر با شناسه‌ی زمینه صدایش می‌زنید. تابع‌هایی که فقط سرآیند اضافه می‌کنند چیزی برنمی‌گردانند؛ تابع‌هایی که ممکن است درخواست را متوقف کنند یک منطقی برمی‌گردانند، پاسخ خطا را خودشان می‌نویسند و رویدادگیر بی‌درنگ برمی‌گردد. ترتیب همیشه در خود رویدادگیر پیداست.

این API کالاها را در حافظه نگه می‌دارد، مسیرهایش را زیر /api/v1 گروه می‌کند، سرآیندهای امنیتی net.http.middleware را اعمال می‌کند و مسیر ساختن را با یک توکن Bearer محافظت می‌کند.

سلام
واردسازی شبکه.اچ تی تی پی
واردسازی شبکه.اچ تی تی پی.میان افزار
واردسازی شبکه.مسیریاب
واردسازی کدگذاری.جیسون
واردسازی تبدیل
واردسازی رشته

ناپایا کالاها := وکتور {} برگردان وکتور<کالا>

ساختار کالا:
    @جیسون "id"
    همگانی شماره: صحیح = ۰
    @جیسون "name"
    همگانی نام: رشته = ""
پایان

تابع مجاز است(زمینه: صحیح۶۴): منطقی:
    اگر اچ تی تی پی.سرصفحه(زمینه، "Authorization") == "Bearer demo-token":
        برگشت درست
    پایان
    اچ تی تی پی.تنظیم وضعیت(زمینه، ۴۰۱)
    اچ تی تی پی.جیسون(زمینه، `{"error":"missing or wrong token"}`)
    برگشت نادرست
پایان

تابع فهرست کالاها(زمینه: صحیح۶۴):
    میان افزار.امن(زمینه)
    اچ تی تی پی.جیسون(زمینه، جیسون.سریال سازی(کالاها))
پایان

تابع نمایش کالا(زمینه: صحیح۶۴):
    میان افزار.امن(زمینه)
    شناسه := تبدیل.رشته به عدد با پیش فرض(اچ تی تی پی.پارامتر(زمینه، "id")، ۰ - ۱)
    هر ک در کالاها:
        اگر ک.شماره == شناسه:
            اچ تی تی پی.جیسون(زمینه، جیسون.سریال سازی(ک))
            برگشت
        پایان
    پایان
    اچ تی تی پی.تنظیم وضعیت(زمینه، ۴۰۴)
    اچ تی تی پی.جیسون(زمینه، `{"error":"not found"}`)
پایان

تابع ساخت کالا(زمینه: صحیح۶۴):
    میان افزار.امن(زمینه)
    اگر وارونه مجاز است(زمینه): برگشت پایان
    نام := جیسون.دریافت(اچ تی تی پی.بدنه(زمینه)، "name")
    اگر نام == "":
        اچ تی تی پی.تنظیم وضعیت(زمینه، ۴۰۰)
        اچ تی تی پی.جیسون(زمینه، `{"error":"name is required"}`)
        برگشت
    پایان
    تازه := کالا { شماره = کالاها.طول() + ۱، نام = رشته.رونوشت(نام) }
    کالاها.بیفزا(تازه)
    اچ تی تی پی.تنظیم وضعیت(زمینه، ۲۰۱)
    اچ تی تی پی.جیسون(زمینه، جیسون.سریال سازی(تازه))
پایان

تابع ریشه:
    ناپایا م := مسیریاب.مسیریاب جدید()
    مسیریاب.گروه(م، "/api/v1"، "GET"، "/items"، فهرست کالاها)
    مسیریاب.گروه(م، "/api/v1"، "GET"، "/items/:id"، نمایش کالا)
    مسیریاب.گروه(م، "/api/v1"، "POST"، "/items"، ساخت کالا)
    ناپایا س := اچ تی تی پی.سرور جدید(۰)
    اچ تی تی پی.استفاده(س، م)
    درگاه := اچ تی تی پی.اجرا در پس زمینه با درگاه(س)
    پایه := "http://127.0.0.1:" + درگاه + "/api/v1"

    الف := اچ تی تی پی.ارسال(پایه + "/items"، `{"name":"چای"}`)
    سرچاپ اچ تی تی پی.وضعیت(الف)، اچ تی تی پی.بدنه(الف)

    ناپایا مجوز := اچ تی تی پی.سرصفحه جدید()
    مجوز.درج("Authorization"، "Bearer demo-token")
    مجوز.درج("Content-Type"، "application/json")
    ب := اچ تی تی پی.ارسال با(پایه + "/items"، `{"name":"چای"}`، مجوز)
    سرچاپ اچ تی تی پی.وضعیت(ب)، اچ تی تی پی.بدنه(ب)

    ج := اچ تی تی پی.دریافت(پایه + "/items/1")
    سرچاپ اچ تی تی پی.وضعیت(ج)، اچ تی تی پی.بدنه(ج)، اچ تی تی پی.دریافت سرصفحه(ج، "x-frame-options")
    سرچاپ اچ تی تی پی.وضعیت(اچ تی تی پی.دریافت(پایه + "/items/9"))
    سرچاپ اچ تی تی پی.بدنه(اچ تی تی پی.دریافت(پایه + "/items"))
پایان
خروجی401 {"error":"missing or wrong token"} 201 {"id":1,"name":"چای"} 200 {"id":1,"name":"چای"} DENY 404 [{"id":1,"name":"چای"}]

جیسون.سریال سازی ساختار را با نام‌هایی که در @جیسون آمده‌اند به JSON تبدیل می‌کند، پس فیلدها در کد فارسی‌اند و کلیدهای JSON انگلیسی می‌مانند. برای احراز هویت واقعی، بسته‌ی jwt توکن‌ها را امضا و بررسی می‌کند و از مسیرها محافظت می‌کند، net.http.session ورود کاربر را با توکن CSRF در یک کوکی نگه می‌دارد، net.http.validate ورودی فرم را بررسی می‌کند و با ۴۰۰ پاسخ می‌دهد، و net.http.swagger API را با OpenAPI مستند می‌کند و صفحه‌ی مستندات را ارائه می‌دهد. همان بسته‌ی اچ تی تی پی کلاینت هم هست، همان‌طور که فراخوانی‌های اچ تی تی پی.ارسال، اچ تی تی پی.ارسال با و اچ تی تی پی.دریافت در این نمونه نشان می‌دهند.

به رشته.رونوشت(نام) در ساخت کالا دقت کنید. مقدارهایی که از درخواست خوانده می‌شوند مال همان درخواست‌اند و وقتی رویدادگیر برمی‌گردد آزاد می‌شوند؛ هر چه برای بعد نگه داشته شود باید رونوشت شود. فراموش کردن این نکته رایج‌ترین اشتباه در نخستین سرور سلام است، و از آن قاعده‌هایی است که یک زبان دارای زباله‌روب هرگز شما را مجبور به فکر کردن درباره‌اش نمی‌کند.

سرور از درون چطور کار می‌کند و چقدر سریع است

روی لینوکس، سرور اتصال‌ها را روی یک نخ می‌پذیرد و به یک استخر مبتنی بر epoll با یک کارگر برای هر هسته‌ی پردازنده می‌سپارد، پس اتصال keep-alive وقتی بیکار است نخی را اشغال نمی‌کند. روی سیستم‌های دیگر هر اتصال یک نخ می‌گیرد. تجزیه‌ی درخواست، مسیریابی و نوشتن پاسخ کد سلام در std/net/http است که همراه برنامه‌ی شما کامپایل می‌شود؛ هیچ کتابخانه‌ی وب C زیر آن نیست.

پروژه این سرور را در ۲۸ اکتبر ۲۰۲۶ در برابر هشت سرور دیگر سنجید که روی یک دستگاه به همان یازده مسیر پاسخ می‌دادند. میانگین هندسی روی هر یازده مسیر:

سروردرخواست در ثانیه
سلام (net.http)۹۴٬۸۵۰
Go، Fiber۶۲٬۴۹۳
Go، Echo۳۵٬۲۳۸
Go، Gin۳۴٬۹۹۹
Go، net/http۳۴٬۹۸۷
Node، Express 5۲۲٬۵۳۶
سرور توکار PHP۱۱٬۹۹۲

روی هفت مسیری که nginx می‌تواند از پیکربندی خودش پاسخ دهد، سلام ۹۴٬۱۵۶ درخواست در ثانیه، Fiber ۶۹٬۶۵۳ و nginx ۶۰٬۴۹۰ را ثبت کردند. بیشترین فاصله در تجزیه‌ی پرسمان روی /search بود: سلام ۹۹٬۱۴۳، Fiber ۴۸٬۲۴۷ و net/http در Go ۳۳٬۱۹۳. کمترین فاصله روی / بود که سلام فقط ۴٪ از Fiber جلوتر بود.

این عددها را با ملاحظاتی بخوانید که خود صفحه‌ی سرعت می‌گوید:

  • دستگاه یک محیط آزمایشی اشتراکی با ۶ پردازنده‌ی مجازی AMD EPYC بود که به خاطر کارهای نامرتبط میانگین باری حدود ۱۱ داشت. سرورها به ۴ هسته و ابزار تولید بار به ۲ هسته‌ی دیگر سنجاق شده بودند، با ۶۴ اتصال keep-alive.
  • بار پس‌زمینه به نفع سرورهایی است که نخ‌های کمی نگه می‌دارند، از جمله سلام. روی یک دستگاه آرام، برتری بر Fiber در میانگین هندسی ۱۶٪ بود و زیر بار ۵۲٪.
  • ردیف پرونده‌ی ایستا تا حدی حافظه‌ی نهان را می‌سنجد: سلام پرونده‌های ایستا را پس از نخستین درخواست در حافظه نگه می‌دارد، در حالی که nginx بدون open_file_cache پیکربندی شده بود.
  • BENCHMARK.md در مخزن، که بعدتر روی یک اجراکننده‌ی ۴ پردازنده‌ی مجازی GitHub دوباره ساخته شد، تصویر نزدیک‌تری نشان می‌دهد: سلام و Fiber در میانگین کلی نزدیک به هم‌اند، و Fiber و nginx روی مسیرهایی که nginx خودش پاسخ می‌دهد کمی جلوترند. سخت‌افزار و بار رتبه‌بندی را تغییر می‌دهند.

جمع‌بندی منصفانه: سرور سلام در این آزمون‌ها هم‌رده‌ی سریع‌ترین چارچوب‌های Go است و به‌روشنی جلوتر از Express و سرور توکار PHP. پیش از اینکه ظرفیت سرورتان را با این عددها برنامه‌ریزی کنید، ابزار بنچمارک را روی سخت‌افزار خودتان اجرا کنید. برای بنچمارک سطح زبان، که در آن سلام در همان محدوده‌ی C و Rust قرار می‌گیرد، مقاله‌ی آیا سلام از C و Rust سریع‌تر است؟ را ببینید.

سرور WebSocket و اتاق‌های پخش همگانی

net.websocket یک اتصال دوطرفه‌ی ماندگار است، با یک هاب برای اتاق‌ها. سمت سرور شامل شنود، پذیرش، دریافت پیام و ارسال متن است؛ ثبت یک اتصال را در یک اتاق می‌گذارد و پخش به همه‌ی اعضای آن می‌فرستد. بارگذاری پیکربندی امن و پذیرش امن لایه‌ی TLS را اضافه می‌کنند، و دریافت با مهلت و پینگ فرست ضربان اتصال را بدون مسدود کردن برنامه مدیریت می‌کنند.

سلام
واردسازی شبکه.وب‌سوکت
واردسازی رشته

ناپایا سرور := وب‌سوکت.سرور {}
ناپایا هاب := وب‌سوکت.هاب جدید()

تابع پذیرش دو اتصال():
    تکرار ۲:
        اتصال := وب‌سوکت.پذیرش(سرور)
        اتاق := رشته.جایگزینی(اتصال.مسیر، "/rooms/"، "")
        وب‌سوکت.ثبت(هاب، اتاق، اتصال)
    پایان
پایان

تابع ریشه:
    سرور = وب‌سوکت.شنود(۰)
    درگاه := وب‌سوکت.درگاه(سرور)
    ن := نخ‌ساز(پذیرش دو اتصال)
    ناپایا علی := وب‌سوکت.شماره گیری("127.0.0.1"، درگاه، "/rooms/prices")
    ناپایا سارا := وب‌سوکت.شماره گیری("127.0.0.1"، درگاه، "/rooms/prices")
    نخ‌پیوند(ن)
    رسیده := وب‌سوکت.پخش(هاب، "prices"، `{"symbol":"GOLD","price":2411.5}`)
    سرچاپ "به"، رسیده، "کاربر رسید"
    سرچاپ "علی گرفت:"، وب‌سوکت.دریافت متن(علی)
    سرچاپ "سارا گرفت:"، وب‌سوکت.دریافت متن(سارا)
    وب‌سوکت.بستن(علی)
    وب‌سوکت.بستن(سارا)
    وب‌سوکت.بستن سرور(سرور)
پایان
خروجیبه 2 کاربر رسید علی گرفت: {"symbol":"GOLD","price":2411.5} سارا گرفت: {"symbol":"GOLD","price":2411.5}

نام اتاق از مسیری می‌آید که کلاینت به آن وصل شده است. یک سرور گفت‌وگوی واقعی در یک حلقه اتصال می‌پذیرد و به هر اتصال نخ یا کار خودش را می‌دهد؛ صفحه‌ی مرجع یک سرور گفت‌وگوی کامل و بررسی توکن هنگام دست‌دادن را آورده است. سرور WebSocket روی درگاه جداگانه‌ی خودش گوش می‌دهد، جدا از سرور net.http. برای Socket.IO هم یک کلاینت در net.socketio هست.

gRPC و HTTP/2 در سلام

grpc پروتکل gRPC را روی بسته‌ی HTTP/2 خود سلام پیاده می‌کند، با فراخوانی‌های یگانه و جریانی، فراداده و کدهای وضعیت استاندارد. پیام‌ها protocol buffer هستند و با encoding.protobuf خوانده و نوشته می‌شوند، که پرونده‌های .proto را هم می‌خواند و از آن‌ها کد سلام می‌سازد. برای یک سرویس سریع، گونه‌های متنی رشته‌های ساده می‌فرستند:

سلام
واردسازی جی آر پی سی
واردسازی همگام سازی

ناپایا سرور := جی آر پی سی.سرور جدید(۰)
ناپایا آماده := همگام سازی.گروه انتظار جدید()

تابع خوشامد(فراخوانی‌شده: صحیح۶۴):
    ناپایا درست‌رسید := نادرست
    نام := جی آر پی سی.دریافت متن(فراخوانی‌شده، درست‌رسید)
    اگر وارونه درست‌رسید یا نام == "":
        جی آر پی سی.شکست(فراخوانی‌شده، جی آر پی سی.وضعیت آرگومان نامعتبر، "نام لازم است")
        برگشت
    پایان
    _ := جی آر پی سی.ارسال متن(فراخوانی‌شده، "سلام، " + نام)
    جی آر پی سی.تنظیم وضعیت(فراخوانی‌شده، جی آر پی سی.وضعیت بدون خطا، "")
پایان

تابع خدمت‌دهی():
    _ := جی آر پی سی.گوش دادن(سرور)
    همگام سازی.اتمام(آماده)
    _ := جی آر پی سی.خدمت به تعداد(سرور، ۱)
پایان

تابع ریشه:
    جی آر پی سی.ثبت متد(جی آر پی سی.مسیر متد("hello.Greeter"، "Greet")، خوشامد)
    همگام سازی.افزودن(آماده، ۱)
    ن := نخ‌ساز(خدمت‌دهی)
    همگام سازی.انتظار(آماده)

    ناپایا کانال := جی آر پی سی.اتصال("127.0.0.1"، جی آر پی سی.درگاه(سرور))
    جی آر پی سی.تنظیم مهلت(کانال، ۵۰۰۰)
    ناپایا وضعیت := جی آر پی سی.وضعیت {}
    پاسخ := جی آر پی سی.فراخوان یگانه متنی(کانال، "/hello.Greeter/Greet"، "سارا"، وضعیت)
    سرچاپ جی آر پی سی.متن وضعیت(وضعیت)، پاسخ
    خالی := جی آر پی سی.فراخوان یگانه متنی(کانال، "/hello.Greeter/Greet"، ""، وضعیت)
    سرچاپ جی آر پی سی.متن وضعیت(وضعیت)، "[" + خالی + "]"
    جی آر پی سی.بستن کانال(کانال)
    نخ‌پیوند(ن)
    جی آر پی سی.توقف سرور(سرور)
    همگام سازی.نابودسازی گروه انتظار(آماده)
پایان
خروجیOK سلام، سارا INVALID_ARGUMENT: نام لازم است []

سرور در این نمونه فقط به یک اتصال خدمت می‌دهد تا برنامه خودش تمام شود؛ سرویس واقعی جی آر پی سی.خدمت را صدا می‌زند. خطاها به شکل کدهای وضعیت gRPC منتقل می‌شوند، پس کلاینتی که به Go، پایتون یا هر زبان دیگری با پشتیبانی gRPC نوشته شده INVALID_ARGUMENT را دقیقاً همان‌طور می‌بیند که از هر سرور gRPC دیگری. برای JSON-RPC 2.0 و MessagePack-RPC بسته‌ی rpc هست و برای GraphQL یک سرور در graphql.

salam serve: سرور وبی که با پیکربندی کار می‌کند

هر سایتی برنامه لازم ندارد. salam serve سرور وب بسته‌ی net.httpd را اجرا می‌کند: در حالت ساده یک پوشه را برای توسعه ارائه می‌کند و با --config چند سایت را از پرونده‌ای اجرا می‌کند که با نحو بلوکی سلام نوشته شده است.

ترمینال
salam serve dist --port=8080                 # پیش‌نمایش یک پوشه
salam serve --config=web.salam --test        # بررسی پیکربندی بدون باز کردن درگاه
salam serve --config=web.salam               # اجرای همه‌ی سایت‌های پیکربندی

حالت پیکربندی این‌ها را دارد: میزبان‌های مجازی که با سرآیند Host انتخاب می‌شوند، تطبیق مسیر به سبک nginx (دقیق، پیشوندی، ^~ و عبارت باقاعده)، تغییر مسیر، سرآیندهای حافظه‌ی نهان، ETag و پاسخ‌های 304، بازه‌های بایتی، صفحه‌های خطا، گزارش دسترسی و پشتوانه‌های FastCGI مثل php-fpm. در نسخه‌ی کنونی نه TLS دارد و نه پراکسی معکوس، برای همین درس salam serve برای HTTPS سرور Caddy یا nginx را جلویش می‌گذارد. همین سرور را می‌توان درون یک برنامه‌ی سلام هم جاسازی کرد، چون این فرمان پوسته‌ای نازک دور همان بسته است.

محدودیت‌هایی که پیش از ساختن روی آن باید بدانید

  • کد جوان. سرور، مسیریاب و بسته‌های پروتکل تازه‌اند و میان نسخه‌ها تغییر می‌کنند. برای محیط عملیاتی نسخه‌ی کامپایلر را ثابت نگه دارید.
  • قاعده‌های دستی حافظه. مقدارهای درخواست وقتی رویدادگیر برمی‌گردد آزاد می‌شوند؛ آنچه نگه می‌دارید را رونوشت کنید، و با اچ تی تی پی.مالکیت (http.Own) رشته‌ای را که خودتان ساخته‌اید برای آزاد شدن به درخواست بسپارید.
  • async/await وجود ندارد. هم‌زمانی با نخ‌ها و استخرهای کار است که در مقاله‌ی برنامه‌نویسی هم‌زمان در سلام آمده است. رویدادگیری که پشت یک فراخوانی کند پایگاه داده منتظر بماند کارگرش را مشغول نگه می‌دارد.
  • اکوسیستم کوچک‌تر. هنوز معادلی برای اکوسیستم بزرگ افزونه‌های Express یا Gin وجود ندارد، و استقرار عملیاتی اندکی هست که بشود از آن آموخت.
  • salam serve جای nginx را نمی‌گیرد. امروز نه TLS دارد و نه proxy_pass.

پرسش‌های پرتکرار

آیا سرور HTTP زبان سلام برای محیط عملیاتی آماده است؟

بک‌اند Salam AI خود پروژه روی همین سرور ساخته شده و ابزار بنچمارکش عمومی است، ولی زبان هنوز به نسخه‌ی ۱٫۰ نرسیده و سرور جوان است. آن را پشت پراکسی‌ای که TLS را پایان می‌دهد یا با اجرای امن اجرا کنید، سقف بدنه و سرآیند را تنظیم کنید و پیش از تکیه بر آن، بار کاری خودتان را آزمون بار کنید.

آیا سلام برای سرور وب از Go سریع‌تر است؟

در بنچمارک مسیریاب پروژه در ۲۸ اکتبر ۲۰۲۶، net/http سلام حدود ۲٫۷ برابر net/http استاندارد Go درخواست در ثانیه پاسخ داد و در میانگین هندسی ۱۶٪ تا ۵۲٪ از Fiber جلوتر بود. اجرای بعدی روی سخت‌افزار دیگر Fiber را بسیار نزدیک‌تر نشان داد. آن را «هم‌رده‌ی سریع‌ترین چارچوب‌های Go» در نظر بگیرید و مورد خودتان را بسنجید.

آیا سلام بدون کتابخانه‌ی اضافه از WebSocket و gRPC پشتیبانی می‌کند؟

بله. net.websocket، net.http2 و grpc بخشی از کتابخانه‌ی استانداردند، به خود سلام نوشته شده‌اند و هیچ کتابخانه‌ی بیرونی C برای نصب لازم ندارند.

آیا می‌توانم سرور وب سلام را روی سرور ابری مستقر کنم؟

سرور به یک فایل اجرایی برای لینوکس، مک یا ویندوز تبدیل می‌شود که در یک کانتینر یا یک ماشین مجازی ساده جا می‌شود. برنامه‌ی net/http را می‌توان برای Cloudflare Workers به WebAssembly هم ساخت، با محدودیت‌هایی که در مقاله‌ی توسعه‌ی فول‌استک با سلام آمده است.

ساختن با سلام

برنامه‌های پایگاه داده در زبان سلام: SQL گونه‌دار، بررسی پرسمان و کد تولیدشده

سلام چطور با پایگاه داده کار می‌کند: یک میانجی اتصال مشترک برای SQLite، MySQL و PostgreSQL، مهاجرت هنگام شروع برنامه، بررسی‌کننده‌ی SQL که طرح‌واره را می‌خواند و مولدی که پرسمان‌های برچسب‌دار را به تابع‌های گونه‌دار تبدیل می‌کند.

خواندن مقاله
ساختن با سلام

گشتی در کتابخانه‌ی استاندارد سلام: از شبکه و رمزنگاری تا پایگاه داده، تصویر و هوش مصنوعی

سلام بیش از ۱۷۰ بسته را همراه کامپایلر عرضه می‌کند. این گشت آن‌ها را حوزه به حوزه مرور می‌کند، چند تایشان را اجرا می‌کند و می‌گوید کتابخانه کجا عمیق است، کجا کم‌عمق، و داشتن این همه چیز در کتابخانه‌ی استاندارد چه هزینه‌ای دارد.

خواندن مقاله
ساختن با سلام

صدا زدن C از زبان سلام: رابط تابع خارجی (FFI) چطور اکوسیستم C را در دسترس می‌گذارد

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

خواندن مقاله