मिश्रित डेटा और फ़ाइल स्थानांतरण के लिए कोई क्यों मल्टीपार्ट / फॉर्म-डेटा का उपयोग करेगा?


14

मैं C # में काम कर रहा हूं और 2 ऐप्स के बीच कुछ संचार कर रहा हूं जो मैं लिख रहा हूं। मुझे वेब एपीआई और JSON पसंद आया है। अब मैं उस बिंदु पर हूं जहां मैं दो सर्वरों के बीच एक रिकॉर्ड भेजने के लिए एक नियमित लिख रहा हूं जिसमें कुछ पाठ डेटा और एक फ़ाइल शामिल है।

इंटरनेट के अनुसार मुझे यहां दिखाए गए अनुसार मल्टीपार्ट / फॉर्म-डेटा अनुरोध का उपयोग करना चाहिए:

SO प्रश्न "C # क्लाइंट से मल्टीपार्ट फॉर्म"

मूल रूप से आप मैन्युअल रूप से एक अनुरोध लिखते हैं जो इस तरह एक प्रारूप का अनुसरण करता है:

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 क्रमांकन और deserialization का उपयोग कहीं भी कर सकते हैं जो हम चाहते हैं। उसके ऊपर, इस डेटा को भेजने का कोड काफी सरल है। आप सिर्फ 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 तक के तार के पार भेजने की आवश्यकता होगी। पहले मैंने फ़ाइल को बाइट सरणी में स्ट्रीम करने के लिए कुछ पंक्तियाँ लिखीं ताकि उस तर्क की तुलना की जा सके जो फ़ाइल में स्ट्रीम होती है और फिर इसे बेस 64 स्ट्रीम में परिवर्तित कर देती है। नीचे कोड के 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

नतीजे यह थे कि साधारण रीड हमेशा 0ms लेता था, लेकिन यह कि Base64 एन्कोडिंग 5ms तक ले गया। नीचे सबसे लंबा समय है:

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 बेहतर नहीं वैसे भी, जो एक सीमांकक के लिए फ़ाइल बाइट्स की जाँच करने के बजाय बेस 64 एन्कोडिंग करने का प्रदर्शन लाभ है।

स्पष्ट रूप से बेस 64 एन्कोडिंग आकार को बढ़ाएगा जैसा कि मैं पहली तालिका में दिखाता हूं, लेकिन इसका वास्तव में यूनिकोड सक्षम यूटीएफ -8 के साथ भी बुरा नहीं है और यदि वांछित है तो अच्छी तरह से संपीड़ित करेगा। लेकिन वास्तविक लाभ यह है कि मेरा कोड अच्छा और साफ है और आसानी से समझ में आता है और यह JSON अनुरोध पेलोड को देखने के लिए मेरी आंखों को चोट नहीं पहुंचाता है।

तो क्यों पृथ्वी पर कोई भी बस आधारभूत रूप में मल्टीपार्ट / फॉर्म-डेटा का उपयोग करने की बजाय बेस 64 एनकोड फाइल को JSON में नहीं करता है? मानक हैं, लेकिन ये अक्सर अपेक्षाकृत बदलते हैं। मानक वास्तव में सिर्फ सुझाव हैं वैसे भी?

जवाबों:


16

multipart/form-dataएचटीएमएल रूपों के लिए बनाया गया एक निर्माण है। जैसा कि आपने पाया है कि पॉजिटिव multipart/form-dataहै ट्रांसफर का आकार ट्रांसफर की जा रही ऑब्जेक्ट के साइज के करीब है - जहां ऑब्जेक्ट के टेक्स्ट एन्कोडिंग में साइज काफी बढ़ जाता है। आप समझ सकते हैं कि जब प्रोटोकॉल का आविष्कार किया गया था तब इंटरनेट बैंडविड्थ सीपीयू चक्रों की तुलना में अधिक मूल्यवान वस्तु थी।

इंटरनेट के अनुसार मुझे एक मल्टीपार्ट / फॉर्म-डेटा अनुरोध का उपयोग करना चाहिए

multipart/form-dataब्राउज़र अपलोड के लिए सबसे अच्छा प्रोटोकॉल है क्योंकि यह सभी ब्राउज़रों द्वारा समर्थित है। सर्वर से सर्वर संचार के लिए इसका उपयोग करने का कोई कारण नहीं है। सर्वर-टू-सर्वर संचार आमतौर पर फॉर्म-आधारित नहीं होता है। संचार ऑब्जेक्ट अधिक जटिल होते हैं और उन्हें घोंसले के शिकार और प्रकार की आवश्यकता होती है - जिन आवश्यकताओं को JSON अच्छी तरह से संभालता है। Base64 एन्कोडिंग द्विआधारी वस्तुओं को आपके द्वारा चुने गए क्रमांकन प्रारूप में स्थानांतरित करने का एक सरल समाधान है। CBOR या BSON जैसे बाइनरी प्रोटोकॉल और भी बेहतर हैं क्योंकि वे बेस 64 की तुलना में छोटी वस्तुओं को अनुक्रमित करते हैं, और वे JSON के काफी करीब हैं कि यह (मौजूदा) JSON संचार के लिए एक आसान एक्सटेंशन होना चाहिए। CPU प्रदर्शन बनाम Base64 के बारे में निश्चित नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.