ทำไมทุกคนจะใช้ข้อมูลหลายส่วน / แบบฟอร์มสำหรับข้อมูลที่หลากหลายและการถ่ายโอนไฟล์?


14

ฉันทำงานใน C # และสื่อสารระหว่าง 2 แอพที่ฉันกำลังเขียน ฉันชอบ Web API และ JSON ตอนนี้ฉันมาถึงจุดที่ฉันกำลังเขียนกิจวัตรประจำวันเพื่อส่งบันทึกระหว่างเซิร์ฟเวอร์ทั้งสองที่มีข้อมูลตัวอักษรและไฟล์อยู่บ้าง

ตามอินเทอร์เน็ตฉันควรใช้คำขอ multipart / form-data ตามที่แสดงที่นี่:

ดังนั้นคำถาม "Multipart form จาก C # client"

โดยทั่วไปคุณเขียนคำขอด้วยตนเองที่ตามรูปแบบดังนี้:

Content-type: multipart/form-data, boundary=AaB03x

--AaB03x
content-disposition: form-data; name="field1"

Joe Blow
--AaB03x
content-disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain

 ... contents of file1.txt ...
--AaB03x--

คัดลอกมาจากRFC 1867 - การอัพโหลดไฟล์แบบฟอร์มเป็น HTML

รูปแบบนี้ค่อนข้างน่าวิตกสำหรับคนที่คุ้นเคยกับข้อมูล JSON ที่ดี ดังนั้นวิธีแก้ไขคือการสร้างคำขอ JSON และ Base64 เข้ารหัสไฟล์และจบลงด้วยคำขอเช่นนี้:

{
    "field1":"Joe Blow",
    "fileImage":"JVBERi0xLjUKJe..."
}

และเราสามารถใช้ประโยชน์จากซีเรียลไลเซชัน JSON และดีซีเรียลไลเซชั่นได้ทุกที่ ยิ่งไปกว่านั้นรหัสในการส่งข้อมูลนี้ค่อนข้างง่าย คุณเพียงแค่สร้างคลาสของคุณสำหรับการทำให้เป็นอันดับ JSON แล้วตั้งค่าคุณสมบัติ คุณสมบัติสตริงไฟล์ถูกตั้งค่าในสองสามบรรทัด:

using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] file_bytes = new byte[fs.Length];
    fs.Read(file_bytes, 0, file_bytes.Length);
    MyJsonObj.fileImage = Convert.ToBase64String(file_bytes);
}

ไม่มีตัวคั่นและส่วนหัวที่โง่มากสำหรับแต่ละรายการ ตอนนี้คำถามที่เหลือคือประสิทธิภาพ ดังนั้นฉันจึงประวัติว่า ฉันมีไฟล์ตัวอย่าง 50 ชุดที่ฉันต้องการส่งข้ามสายที่มีตั้งแต่ 50KB ถึง 1.5MB หรือมากกว่านั้น ก่อนอื่นฉันเขียนบางบรรทัดเพื่อสตรีมในไฟล์ไปยังอาร์เรย์ไบต์เพื่อเปรียบเทียบกับตรรกะที่สตรีมในไฟล์แล้วแปลงเป็นสตรีม Base64 ด้านล่างนี้เป็นโค้ด 2 ชิ้นที่ฉันทำโปรไฟล์:

สตรีมไปยังโปรไฟล์หลายส่วน / แบบฟอร์มข้อมูลโดยตรง

var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] test_data = new byte[fs.Length];
    fs.Read(test_data, 0, test_data.Length);
}
timer.Stop();
long test = timer.ElapsedMilliseconds;
//Write time elapsed and file size to CSV file

สตรีมและเข้ารหัสเพื่อสร้างโปรไฟล์คำขอ JSON

var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] file_bytes = new byte[fs.Length];
    fs.Read(file_bytes, 0, file_bytes.Length);
    ret_file = Convert.ToBase64String(file_bytes);
}
timer.Stop();
long test = timer.ElapsedMilliseconds;
//Write time elapsed, file size, and length of UTF8 encoded ret_file string to CSV file

ผลลัพธ์คือการอ่านที่เรียบง่ายใช้เวลาเสมอ 0 มิลลิวินาที แต่การเข้ารหัส Base64 ใช้เวลาสูงสุด 5 มิลลิวินาที ด้านล่างเป็นเวลาที่ยาวที่สุด:

File Size  |  Output Stream Size  |  Time
1352KB        1802KB                 5ms
1031KB        1374KB                 7ms
463KB         617KB                  1ms

อย่างไรก็ตามในการผลิตคุณจะไม่เขียนสุ่มหลายส่วน / ข้อมูลแบบสุ่มโดยไม่ตรวจสอบตัวคั่นของคุณก่อนใช่มั้ย ดังนั้นฉันจึงแก้ไขโค้ดข้อมูลฟอร์มเพื่อตรวจสอบไบต์ตัวคั่นในไฟล์ของตัวเองเพื่อให้แน่ใจว่าทุกอย่างจะถูกแยกวิเคราะห์ได้ ฉันไม่ได้เขียนอัลกอริธึมการสแกนที่ได้รับการปรับปรุงดังนั้นฉันจึงทำให้ตัวคั่นมีขนาดเล็กเพื่อไม่ให้เสียเวลา

var timer = new Stopwatch();
timer.Start();
using (FileStream fs = File.Open(file_path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] test_data = new byte[fs.Length];
    fs.Read(test_data, 0, test_data.Length);
    string delim = "--DXX";
    byte[] delim_checker = Encoding.UTF8.GetBytes(delim);

    for (int i = 0; i <= test_data.Length - delim_checker.Length; i++)
    {
        bool match = true;
        for (int j = i; j < i + delim_checker.Length; j++)
        {
            if (test_data[j] != delim_checker[j - i])
            {
                match = false;
                break;
            }
        }
        if (match)
        {
            break;
        }
    }
}
timer.Stop();
long test = timer.ElapsedMilliseconds;

ตอนนี้ผลแสดงให้ฉันเห็นว่าวิธีการแบบฟอร์มข้อมูลจะช้าลงอย่างมีนัยสำคัญ ด้านล่างเป็นผลลัพธ์ที่มีเวลา> 0ms สำหรับวิธีใดวิธีหนึ่ง:

File Size | FormData Time | Json/Base64 Time
181Kb       1ms             0ms
1352Kb      13ms            4ms
463Kb       4ms             5ms
133Kb       1ms             0ms
133Kb       1ms             0ms
129Kb       1ms             0ms
284Kb       2ms             1ms
1031Kb      9ms             3ms

ดูเหมือนว่าอัลกอริทึมที่ได้รับการเพิ่มประสิทธิภาพจะทำได้ดีกว่ามากหากคุณเห็นว่าตัวคั่นของฉันมีความยาวเพียง 5 ตัวอักษร ไม่ใช่เรื่องที่ดีกว่านี้อีก 3x ซึ่งเป็นข้อได้เปรียบด้านประสิทธิภาพของการเข้ารหัส Base64 แทนการตรวจสอบไบต์ไฟล์สำหรับตัวคั่น

เห็นได้ชัดว่าการเข้ารหัส Base64 จะขยายขนาดตามที่ฉันแสดงในตารางแรก แต่จริงๆแล้วมันไม่ได้แย่ขนาดนั้นถึงแม้จะใช้ Unicode ที่มีความสามารถ UTF-8 และจะบีบอัดได้ดีหากต้องการ แต่ประโยชน์ที่แท้จริงคือรหัสของฉันนั้นดีและสะอาดและเข้าใจได้ง่ายและไม่ทำให้ลูกตาของฉันเจ็บเมื่อต้องดู JSON ขอน้ำหนักบรรทุกที่มาก

เหตุใดในโลกนี้ทุกคนจะไม่เพียงแค่เข้ารหัสไฟล์ Base64 ใน JSON แทนที่จะใช้หลายส่วน / ฟอร์มข้อมูล มีมาตรฐาน แต่สิ่งเหล่านี้เปลี่ยนแปลงค่อนข้างบ่อย มาตรฐานเป็นเพียงข้อเสนอแนะจริง ๆ ใช่มั้ย

คำตอบ:


16

multipart/form-dataเป็นโครงสร้างที่สร้างขึ้นสำหรับฟอร์ม HTML ในขณะที่คุณค้นพบว่าข้อดีของmultipart/form-dataมันคือขนาดการถ่ายโอนนั้นใกล้กับขนาดของวัตถุที่กำลังถ่ายโอนซึ่งในการเข้ารหัสข้อความของวัตถุขนาดจะขยายใหญ่ขึ้นอย่างมาก คุณสามารถเข้าใจได้ว่าแบนด์วิธอินเทอร์เน็ตเป็นสิ่งที่มีค่ามากกว่าซีพียูรอบเมื่อมีการคิดค้นโปรโตคอล

ตามอินเทอร์เน็ตฉันควรใช้คำขอ multipart / form-data

multipart/form-dataเป็นโปรโตคอลที่ดีที่สุดสำหรับการอัปโหลดเบราว์เซอร์เพราะเบราว์เซอร์รองรับทั้งหมด ไม่มีเหตุผลที่จะใช้เพื่อการสื่อสารระหว่างเซิร์ฟเวอร์กับเซิร์ฟเวอร์ การสื่อสารระหว่างเซิร์ฟเวอร์กับเซิร์ฟเวอร์มักไม่ได้ใช้แบบฟอร์ม วัตถุการสื่อสารมีความซับซ้อนและต้องการการซ้อนและประเภท - ข้อกำหนดที่ JSON จัดการได้ดี การเข้ารหัส Base64 เป็นวิธีที่ง่ายสำหรับการถ่ายโอนวัตถุไบนารีในรูปแบบการทำให้เป็นอนุกรมที่คุณเลือก โพรโทคอลไบนารีเช่นCBORหรือBSONดียิ่งขึ้นเนื่องจากพวกเขาเป็นอนุกรมวัตถุขนาดเล็กกว่า Base64 และพวกเขาอยู่ใกล้พอที่จะ JSON ที่มัน (ควรจะ) ส่วนขยายที่ง่ายต่อการสื่อสาร JSON ที่มีอยู่ ไม่แน่ใจเกี่ยวกับประสิทธิภาพของ CPU กับ Base64

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.