توسعه فرانت‌اند

Protobuf و gRPC-web؛ قرارداد و محدودیت API مرورگر

تفاوت Protobuf و gRPC-web، شماره فیلد و Presence، تولید کد، Envoy و حالت‌های RPC مرورگر؛ بدون ادعای عمومی سرعت یا اندازه ثابت.

1404/12/21 1 دقیقه مطالعه 1,095 بازدید

Protobuf و gRPC-web دو مسئولیت متفاوت دارند. Protobuf شکل پیام و روش Serialization را تعریف می‌کند؛ gRPC-web مسیر استفاده از قراردادهای gRPC در Client مرورگر را فراهم می‌کند. باینری بودن داده به تنهایی ارتباط سریع‌تر، امنیت بیشتر یا API درست نمی‌سازد. انتخاب این مسیر باید با اندازه پیام، تعداد مصرف‌کنندگان و ابزارهای Backend هماهنگ باشد. اگر تیم فقط به یک فرم ساده با چند درخواست نیاز دارد، هزینه Code Generation و Proxy هم باید در تصمیم دیده شود.

ادعای «پنج تا ده برابر کوچک‌تر و سریع‌تر از JSON» برای همه داده‌ها قابل دفاع نیست. ساختار پیام، تعداد رشته‌ها، نوع عدد، فشرده‌سازی و Runtime روی نتیجه اثر دارند. حجم خام و حجم انتقال پس از فشرده‌سازی یک معیار نیستند. زمان Serialization هم فقط بخشی از تأخیر است؛ Query، شبکه و آماده شدن Client می‌توانند غالب باشند. عنوان دقیق‌تر این موضوع، قرارداد و محدودیت API مرورگر است و نباید با عدد ثابت وعده عملکرد بدهد.

Protobuf قرارداد پیام را با شماره فیلد نگه می‌دارد

راهنمای proto3 تعریف Message، نوع و شماره فیلد را توضیح می‌دهد. شماره فیلد در قالب Wire نقش دارد و صرفاً ترتیب نمایش در فایل نیست. حذف یک فیلد نباید با استفاده دوباره از همان شماره برای معنی تازه همراه شود؛ Reserved کردن شماره و نام حذف‌شده به تکامل قرارداد کمک می‌کند. یک تغییر ظاهراً کوچک در Schema می‌تواند Client قدیمی را با برداشت نادرست از داده روبه‌رو کند.

نوع string به معنی ایمیل معتبر یا شناسه مجاز نیست و عددی بودن quantity به معنی مثبت بودن آن نیست. این قواعد در بررسی Runtime و دامنه اعمال می‌شوند. انتخاب نوع عدد هم با محدوده زبان مقصد هماهنگ باشد؛ عددهای بزرگ ممکن است در JavaScript نمایشی متفاوت از انتظار داشته باشند. تیم باید مشخص کند Library تولیدشده مقدار را چگونه ارائه می‌کند. مقاله TypeScript پیشرفته درباره مرز نوع و اعتبار واقعی داده توضیح دارد.

Presence و مقدار پیش‌فرض را با نیاز دامنه انتخاب کنید

نبود فیلد با وجود فیلدی دارای مقدار صفر همیشه معنی یکسانی ندارد. برای مثال فرضی، صفر بودن مبلغ می‌تواند معتبر باشد، در حالی که نامعلوم بودن مبلغ نیازمند بررسی است. Schema باید این تفاوت را با سازوکار مناسب Presence یا مدل داده نشان دهد. فرض اینکه هر فیلد تولیدشده حتماً از Server آمده است، می‌تواند نتیجه اشتباه بسازد. مقدار پیش‌فرض را در قرارداد به عنوان واقعیت تجاری معرفی نکنید مگر همان معنی تعریف شده باشد.

Enum نیز به تکامل توجه می‌خواهد. Client باید با مقدار ناشناخته یا وضعیت اضافه‌شده رفتار مشخص داشته باشد. در رابط سفارش، تبدیل همه وضعیت‌های نامعلوم به موفقیت انتخاب مناسبی نیست. پیام محدودیت یا مسیر دریافت تازه می‌تواند لازم باشد. یک Schema با نام‌های روشن و قواعد تغییر، از فهرست فیلدهایی که فقط برای تولید کد نوشته شده مفیدتر است. Nullability، Presence و حالت خطا باید با مصرف‌کننده و مدل محصول بررسی شوند.

Wire Format را از رفتار سرویس جدا کنید

مستند Encoding در Protobuf ساختار Tag، Wire Type و نمایش بعضی مقدارها را توضیح می‌دهد. این سازوکار می‌تواند پیام فشرده‌ای برای بعضی داده‌ها بسازد، اما خود آن Query یا RPC را تعریف نمی‌کند. انتقال یک فایل Protobuf با HTTP، به تنهایی gRPC-web نیست. Service، Method، Metadata و Status بخشی از لایه ارتباط‌اند و مصرف‌کننده باید آن‌ها را با همان قرارداد بشناسد.

Serialization رمزنگاری نیست. باینری بودن، خواندن مستقیم توسط انسان را کمتر آسان می‌کند ولی مانع دسترسی کاربر یا مهاجم به داده نمی‌شود. اطلاعات خصوصی نباید به امید ناخوانا بودن فرمت ارسال شوند. TLS مسیر انتقال را حفاظت می‌کند و مجوز Server تعیین می‌کند چه داده‌ای قابل ارسال است. Logging هم باید اطلاعات لازم برای خطایابی را نگه دارد و Message حساس را بی‌دلیل به متن عمومی Log تبدیل نکند.

مرورگر از مسیر gRPC-web استفاده می‌کند

مخزن رسمی gRPC-web Client مرورگر و اتصال از طریق Proxy مناسب، با Envoy در مسیر متداول، را معرفی می‌کند. عبارت «مستقیماً از مرورگر به gRPC معمولی» این مرز را پنهان می‌کند. Client تولیدشده باید به Endpointی وصل شود که gRPC-web را می‌پذیرد. اگر Backend پشتیبانی مناسب دیگری دارد، معماری ممکن است تغییر کند؛ وجود HTTP/2 در مرورگر به تنهایی همه رفتار gRPC Native را در اختیار JavaScript قرار نمی‌دهد.

مسیر عملی شامل Schema، تولید کد Client، پیاده‌سازی Server و لایه دریافت درخواست مرورگر است. آموزش رسمی gRPC-web این بخش‌ها را در یک نمونه کامل نشان می‌دهد. یک فایل proto بدون این اجزا، برنامه قابل اجرای مرورگر نیست. در برنامه واقعی، Package و Pluginهای تولید کد باید با نسخه Runtime و روش Bundle هماهنگ باشند. تولید فایل موفق به معنی دریافت موفق داده یا تنظیم درست CORS نیست.

نوع Streaming را پیش از انتخاب بررسی کنید

در مستند فعلی پیاده‌سازی رسمی، Unary و Server-side Streaming پشتیبانی می‌شوند و Server Streaming به grpcwebtext وابسته است. Client-side و Bidirectional Streaming در همان پیاده‌سازی پشتیبانی نمی‌شوند. بنابراین نباید قابلیت‌های همه حالت‌های gRPC را به Client مرورگر نسبت داد. برای گفت‌وگوی دوطرفه پیوسته یا همکاری زنده، ابتدا نیاز واقعی را با این محدودیت مقایسه کنید. مقاله WebSocket مسیر دیگری برای ارتباط دوطرفه معرفی می‌کند.

grpcwebtext داده را با Base64 منتقل می‌کند و حالت grpcweb از قالب باینری استفاده می‌کند؛ انتخاب حالت با قابلیت مورد نیاز هماهنگ شود. سربار بسته‌بندی و Proxy در اندازه انتقال اثر دارد. مقایسه حجم فقط با Message خام Protobuf تصویر کامل نمی‌دهد. اگر فقط Unary لازم است، هزینه و سازگاری هر حالت را بررسی کنید. تصمیم نباید با این فرض گرفته شود که همه Clientهای gRPC-web بدون تفاوت، هر نوع Stream را مصرف می‌کنند.

تولید کد را بخشی از Build نگه دارید

protoc، Plugin تولید پیام و Plugin gRPC-web مسئولیت‌های متفاوت دارند. نصب یک Runtime npm الزاماً همه ابزارهای تولید را فراهم نمی‌کند. روش خروجی CommonJS یا TypeScript باید با Bundler پروژه سازگار باشد و importها به فایل‌های واقعی اشاره کنند. در تحویل، محل Schema و دستور تولید ثبت شود. اگر Client را دستی ویرایش کنید، تولید بعدی ممکن است تغییر را از بین ببرد؛ منطق محصول در لایه‌ای بیرون فایل Generated قرار گیرد.

نسخه ابزارها را همراه Lockfile و روند تولید مشخص کنید. تغییر Schema باید با بازتولید Client و بررسی مصرف‌کنندگان همراه باشد. دو تیم که از نسخه‌های متفاوت فایل proto استفاده می‌کنند ممکن است قراردادهای متفاوت ببینند، حتی اگر نام سرویس یکی باشد. مقاله انتخاب الگوی API درباره مالکیت Schema و هزینه نگهداری زمینه دارد. قرارداد مشترک زمانی مفید است که تغییر آن هم فرایند مشترک و قابل پیگیری داشته باشد.

Proxy و مرورگر مرزهای عملیاتی دارند

فیلتر gRPC-Web در Envoy لایه پشتیبانی مربوط را معرفی می‌کند. تنظیم Route، Upstream، Timeout و فیلترهای لازم باید با سرویس واقعی هماهنگ باشند. YAML عمومی بدون آدرس و قرارداد مناسب، استقرار کامل نیست. CORS نیز باید Origin و Headerهای لازم را مشخص کند؛ باز کردن بی‌حد همه Originها جای بررسی مدل Authentication را نمی‌گیرد. رفتار Browser Client با Client سرویس داخلی یکسان فرض نشود.

اگر Authentication با نشست یا Token انجام می‌شود، انتقال و انقضای آن را در Metadata و سمت Server تعریف کنید. مجوز هر Method یا منبع همچنان لازم است. خطای Proxy باید از Status تجاری سرویس قابل تفکیک باشد تا Client پیام مناسب نشان دهد. کاربر نباید Timeout را به عنوان ثبت نشدن قطعی عملیات بفهمد اگر نتیجه واقعاً نامعلوم است. Retry عملیات تغییر داده نیازمند Idempotency و روش بررسی نتیجه است، نه صرفاً فراخوانی دوباره همان Method.

ارزیابی را با سناریوی کامل انجام دهید

یک سناریوی نماینده انتخاب کنید: پیام‌های کوچک پرتعداد، پاسخ بزرگ یا جریان یک‌طرفه. حجم Wire، زمان Client، زمان Server و تأخیر انتهابه‌انتها معیارهای متفاوت‌اند. اگر JSON با فشرده‌سازی و Protobuf بدون آن مقایسه می‌شوند، شرایط را صریح بنویسید. Bundle Client و هزینه تولید کد هم بخشی از تصمیم محصول هستند. نتیجه یک نمونه کوچک را به همه داده‌ها تعمیم ندهید و اعداد فرضی را به عنوان Benchmark واقعی معرفی نکنید.

برای تحویل، Schema و قواعد تکامل، حالت RPC، نسخه تولید کد، مسیر Proxy و روش خطا را در یک قرارداد کوتاه نگه دارید. مقاله TypeScript با React برای مدل State رابط مفید است. انتخاب مناسب وقتی روشن می‌شود که بدانید Browser چه عملی می‌خواهد، کدام بخش‌ها لازم‌اند و تیم چگونه آن‌ها را نگه می‌دارد. وعده سرعت بدون این مسیر کامل، کمکی به تصمیم درباره API قابل اجرا و قابل پیگیری نمی‌کند.

واکنش به این مقاله

اشتراک‌گذاری این مقاله:
دیدگاه‌ها 0
۰ / ۲۰۰۰

هنوز دیدگاهی ثبت نشده

اولین نفری باشید که نظر می‌دهد!