در دریافتِ تدریجیِ NDJSON،هر chunkالزاماً یک رکورد نیست؛ممکن است وسطِ یک حرفِ فارسی تمام شود یا چند رکورد را یکجا بیاورد. مرزِ رکورد را باید از قراردادِ newlineوJSONمعتبر بخوانیم. این تمرین یک جریانِ سهرکوردیِ اصیل را در تمامِ مرزهای دوتکه و همچنین بایتبهبایت میخواند و همان سه شیء را میخواهد.
قراردادِ NDJSON را از بستهبندیِ دریافت جدا کنیم
مشخصاتِ جامعهمحورِ NDJSONنسخهٔ۱٫۰٫۰،هر متنِ JSONرا باLFتمام میکند وCRپیش ازLFرا هم میپذیرد؛کدگذاری UTF-8است. آن را استانداردِ IETFیا قراردادِ خودکارِ هرSDKنمینامیم. این parserیک زیرمجموعهٔ محدود دارد:هر رکورد باید شیء باشد،هرچند مقدارهایJSONدر اصل فقط شیء نیستند.
سقفِ محلیِ هر رکورد۲۵۶بایتِ متن،بدونِ جداکنندهٔLFیاCRLF،و سقفِ یک ورودیِ feedبرابر۴۰۹۶بایت است. این اعداد انتخابِ آموزشیاند،نه سهمیهٔ اپرا یا پروتکل. نگهداریِ همهٔ رکوردهایِ خروجی در این فایل،طراحیِ جامعِ streamِ بینهایت یا تضمینِ مصرفِ حافظه نیست؛محدودیت را دقیق مینویسیم.
سه رکورد با مرزهای متفاوت
رکوردِ اول متنِ «سلام 🙂» دارد؛دومی یک مقدارِ دارای خطِ جدیدِ معنایی میانِ «خط اول» و«خط دوم»؛سومی شیء داخلی باok=trueدارد. تولیدکنندهٔ محلی newlineداخلِ رشتهٔ دوم را escapeمیکند؛آن مقدار نباید دو رکوردِ فیزیکی شود. بینِ رکوردِ اول و دوم یک خطِ خالیِ عمدی هم گذاشتهایم.
جداکنندهٔ یکی از رکوردهاLFو دیگریCRLFاست. oracleهمان فهرستِ سه شیءِ اولیه است،نه تفسیرِ بصریِ خطهای خروجی. بایتهای دقیقِ جریان درJSONبهشکلhexآمدهاند؛اینhexخودِJSONمتنیِ قابلِparseنیست و برای دیدنِ مرزهای بایت ثبت شده است.
بافر را تا LFنگه داریم
feedبایتها را به بافرِ محدود اضافه میکند؛تاLFنرسیده،رکوردِ نهایی تحویل نمیدهد. پس از پیداشدنِLF،حداکثر یکCRانتهایی برایCRLFحذف میشود؛هرCRخامِ باقیمانده،حتی میانِ توکنهایJSON،رد میشود. سپس بودجهٔ رکورد کنترل و همان خط باUTF-8ِstrictخوانده میشود. سپسJSONparseمیشود و فقط بعد از موفقیت،شیء واردِ خروجی میشود.
به همین دلیل بریدنِ chunkوسطِ توالیِ چندبایتیِ «سلام» خطا نیست؛بایتِ ناقص تا ادامه در بافر میماند. اماUTF-8ِ خرابِ یک خطِ کامل واقعاً رد میشود. این روش برای قراردادِ newlineِNDJSONاست،نه parserِ قالبِ باینریِ صوت،SSEیا مرزبندیِ پاسخِ مدل.
مرزِ دریافت را واقعاً تغییر دادیم
| نحوهٔ دادنِ همان بایتها | انتظارِ آزمون |
|---|---|
| تمامِ موقعیتهای دو قسمت | همان سه شیء،برابرِ oracle |
| هر بار یک بایت | فارسی و ایموجی بدون خرابی بازمیگردند |
| تمامِ جریان در یکchunk | چند رکورد جدا خوانده میشوند |
| خطِ خالی با تنظیمِ غیرفعال | ردِ صریح،نه حذفِ پنهانی |
تعدادِ موقعیتهای اجراشده از طولِ واقعیِ streamبهعلاوهٔ۱در گزارش ثبت میشود. این پوششِ تمامِ مرزهای همان ورودیِ کوچک است،نه اثباتِ درستی برای تمامِ streamهای ممکن یاbenchmarkِ سرعتِ شبکه.
EOFرا با پایانِ معتبرِ رکورد یکی نکنیم
قراردادِ این نسخه LFِ نهایی را لازم میداند. حتی اگربافرِ باقیمانده ظاهراًJSONکامل باشد،finishبا نبودِLFخطا میدهد؛از قطعِ ورودی،کاملبودنِ رکورد را حدس نمیزند. در حالتِ عادی بافرِ خالی،finishخروجی را نهایی و parserرا بسته میکند؛بعد از آنfeedمجاز نیست.
نه ورودیِ منفی اجرا شدهاند:UTF-8خراب،JSONنامعتبر،کلیدِ تکراریِ داخلی،LFنهاییِ مفقود،رکوردِ بزرگتر از سقف،خطِ جدیدِ فیزیکیِ escapeنشده داخلِ رشته،NaN،CRخامِ داخلی ودوCRپیش ازLF. دو حالتِCRدر تمامِ مرزهای دوتکه هم واقعاً رد میشوند؛سهلگیریِJSONبرایwhitespaceنباید قراردادِNDJSONرا عوض کند. خطِ خالی هم با گزینهٔignore_empty=Falseرد میشود؛رفتارِ پیشفرضِ نادیدهگرفتنِ آن مستند و قابلِ تغییر است.
کلیدِ تکراری و تولیدِ امن را دوباره اختراع نکنیم
کنترلِ object_pairs_hookدر هر شیء،کلیدِ رمزگشاییشدهٔ تکراری را رد میکند؛توضیحِ کاملِ این خطا در کلیدِ تکراریِ JSON موجود است. خروجیِ مستقلِ این صفحه مرزبندیِ تدریجی وdecodeِUTF-8است. کدگذاریِ خروجیِ لاگ هم سمتِ تولیدکننده را بررسی میکند و جایِ این گیرنده را نمیگیرد.
فایل فقط بایتهای ساختگی در حافظه را میخواند؛socket،APIیا صوتِ واقعی ندارد. برای اتصال در راهکارهای اپرا،اگر دریافتِ رکوردی لازم است،نوعِ محتوا،مرزِ رکورد،رفتارِ قطع و سقفها را از مستنداتِ همان مسیر بگیرید. پشتیبانیِ NDJSONیاSSEدر اپرا از این تمرین نتیجه نمیشود.
فایل تمرین و منبع
کدِ کاملِ محلی و کنترلهای اصیلِ تمرین · دادهٔ ساختگی و خروجیِ اجرای واقعی
- مشخصاتِ جامعهمحورِ NDJSONنسخه۱٫۰٫۰،بخشهای۳٫۱تا۳٫۳؛بهروزرسانیِ ثبتشده۱۹اکتبر۲۰۱۴؛خبرِ تازه نیست
- RFC8259،دسامبر۲۰۱۷؛بخشهای رشته وUTF-8؛فقط بخشهای مرتبط خوانده شدند
منابع در 2026-11-04 خوانده شدند؛ این تاریخ، تاریخ انتشار منبع نیست. مثالها و فایلهای این راهنما آموزشی و ساختهٔ تحریریهاند.