REST API - फाइल (यानी इमेजेज) प्रोसेसिंग - बेस्ट प्रैक्टिस


197

हम REST API के साथ सर्वर विकसित कर रहे हैं, जो JSON के साथ स्वीकार और प्रतिक्रिया करता है। समस्या यह है, अगर आपको क्लाइंट से सर्वर पर चित्र अपलोड करने की आवश्यकता है।

नोट: और यह भी कि मैं एक ऐसे उपयोग-मामले के बारे में बात कर रहा हूँ जहाँ इकाई (उपयोगकर्ता) में कई फाइलें (carPhoto, लाइसेंस-फोटो) हो सकती हैं और अन्य गुण (नाम, ईमेल ...) भी हो सकते हैं, लेकिन जब आप नया उपयोगकर्ता बनाते हैं, तो आप डॉन टी इन छवियों को भेजते हैं, उन्हें पंजीकरण प्रक्रिया के बाद जोड़ा जाता है।


जिन समाधानों से मैं अवगत हूं, लेकिन उनमें से प्रत्येक में कुछ खामियां हैं

1. JSON के बजाय मल्टीपार्ट / फॉर्म-डेटा का उपयोग करें

अच्छा : POST और PUT अनुरोध जितना संभव हो उतना Restful हैं, वे फ़ाइल के साथ पाठ इनपुट शामिल कर सकते हैं।

विपक्ष : यह अब JSON नहीं है, जो मल्टीगार्ट / फॉर्म-डेटा की तुलना में परीक्षण, डिबग आदि के लिए बहुत आसान है

2. अलग फ़ाइलों को अद्यतन करने की अनुमति दें

नए उपयोगकर्ता बनाने के लिए POST अनुरोध छवियों को जोड़ने की अनुमति नहीं देता है (जो हमारे उपयोग के मामले में ठीक है कि मैंने शुरुआत में कैसे कहा था), चित्रों को अपलोड करना उदाहरण के लिए मल्टीपार्ट / फॉर्म-डेटा के रूप में / उपयोगकर्ताओं / 4 / carPhoto द्वारा अनुरोध किया जाता है

अच्छा : सब कुछ (फ़ाइल अपलोडिंग को छोड़कर) JSON में ही रहता है, परीक्षण करना आसान है और डीबग (आप अपनी लंबाई से डर के बिना JSON के अनुरोधों को पूरा कर सकते हैं)

विपक्ष : यह सहज नहीं है, आप POST या PUT के सभी वैरिएबल को एक ही बार में कैंट /users/4/carPhotoकर सकते हैं और इस पते को एक संग्रह के रूप में अधिक माना जा सकता है (REST API के लिए मानक उपयोग-केस इस तरह दिखता है /users/4/shipments)। आमतौर पर आप (और न चाहते हैं) इकाई के प्रत्येक चर को प्राप्त / प्राप्त कर सकते हैं, उदाहरण के लिए उपयोगकर्ता / 4 / नाम। आप GET के साथ नाम प्राप्त कर सकते हैं और इसे PUT के साथ उपयोगकर्ताओं / 4 में बदल सकते हैं। यदि आईडी के बाद कुछ है, तो यह आमतौर पर उपयोगकर्ताओं / 4 / समीक्षाओं की तरह एक और संग्रह है

3. बेस 64 का उपयोग करें

इसे JSON के रूप में भेजें लेकिन Base64 के साथ फ़ाइलों को एन्कोड करें।

अच्छा : पहले समाधान के रूप में ही, यह यथासंभव सेवा है।

विपक्ष : एक बार फिर, परीक्षण और डिबगिंग बहुत खराब है (शरीर में मेगाबाइट डेटा हो सकता है), आकार में वृद्धि और प्रसंस्करण समय दोनों में भी है - क्लाइंट और सर्वर


मैं वास्तव में समाधान सं का उपयोग करना चाहूंगा। 2, लेकिन यह अपने विपक्ष है ... कोई भी मुझे "सबसे अच्छा क्या है" समाधान की बेहतर जानकारी दे सकता है?

मेरा लक्ष्य रेस्टफुल सेवाओं को यथासंभव अधिक मानकों के साथ रखना है, जबकि मैं इसे यथासंभव सरल रखना चाहता हूं।


आपको यह भी उपयोगी लग सकता है: stackoverflow.com/questions/4083702/…
मार्कॉन

5
मुझे पता है कि यह विषय पुराना है लेकिन हमने हाल ही में इस मुद्दे का सामना किया है। सबसे अच्छा दृष्टिकोण जो हमें मिला है वह आपकी संख्या 2 के समान है। हम फ़ाइलों को सीधे एपीआई में अपलोड करते हैं और फिर इन फाइलों को मॉडल में संलग्न करते हैं। इस परिदृश्य के साथ, आप प्रपत्र के रूप में, उसके बाद या उसी पृष्ठ पर अपलोड छवियां बना सकते हैं, वास्तव में कोई फर्क नहीं पड़ता। अच्छी चर्चा!
टियागो माटोस

2
@TiagoMatos - हाँ, ठीक है, मैंने इसे एक उत्तर में वर्णित किया है जिसे मैंने हाल ही में स्वीकार किया है
libik

6
यह सवाल पूछने के लिए धन्यवाद।
जुहैर ताहिर

1
"यह भी पता / उपयोगकर्ताओं / 4 / carPhoto एक संग्रह के रूप में अधिक माना जा सकता है" - नहीं, यह एक संग्रह की तरह नहीं दिखता है और जरूरी नहीं कि इसे एक माना जाएगा। किसी संसाधन से संबंध रखना पूरी तरह से ठीक है जो कि संग्रह नहीं बल्कि एकल संसाधन है।
B12Toaster

जवाबों:


155

यहाँ ओपी (मैं दो साल बाद इस सवाल का जवाब दे रहा हूं, डैनियल सेरेकेडो द्वारा की गई पोस्ट एक समय में खराब नहीं थी, लेकिन वेब सेवाएं बहुत तेजी से विकसित हो रही हैं)

तीन साल के पूर्णकालिक सॉफ्टवेयर विकास (सॉफ्टवेयर आर्किटेक्चर, प्रोजेक्ट मैनेजमेंट और माइक्रो सर्विस आर्किटेक्चर पर ध्यान देने के साथ) के बाद मैं निश्चित रूप से सबसे अच्छा के रूप में दूसरा तरीका (लेकिन एक सामान्य समापन बिंदु के साथ) चुनता हूं।

यदि आपके पास छवियों के लिए एक विशेष समापन बिंदु है, तो यह आपको उन चित्रों को संभालने की अधिक शक्ति प्रदान करता है।

मोबाइल एप्लिकेशन (iOS / Android) और फ्रंटएंड (React का उपयोग करके) दोनों के लिए हमारे पास एक ही REST API (Node.js) है। यह 2017 है, इसलिए आप छवियों को स्थानीय रूप से संग्रहीत नहीं करना चाहते हैं, आप उन्हें कुछ क्लाउड स्टोरेज (Google क्लाउड, एस 3, क्लाउडिनरी, ...) पर अपलोड करना चाहते हैं, इसलिए आप उन पर कुछ सामान्य हैंडलिंग चाहते हैं।

हमारा सामान्य प्रवाह यह है कि जैसे ही आप एक छवि का चयन करते हैं, यह पृष्ठभूमि पर अपलोड करना शुरू कर देता है (आमतौर पर POST / चित्र समापन बिंदु), अपलोड करने के बाद आपको आईडी लौटाता है। यह वास्तव में उपयोगकर्ता के अनुकूल है, क्योंकि उपयोगकर्ता एक छवि चुनते हैं और फिर आम तौर पर कुछ अन्य क्षेत्रों (जैसे पता, नाम, ...) के साथ आगे बढ़ते हैं, इसलिए जब वह "भेजें" बटन हिट करता है, तो छवि आमतौर पर पहले से ही अपलोड होती है। वह इंतजार नहीं करता है और स्क्रीन पर "अपलोडिंग ..." कहकर देख रहा है।

वही चित्र प्राप्त करने के लिए जाता है। विशेष रूप से मोबाइल फोन और सीमित मोबाइल डेटा के लिए धन्यवाद, आप मूल चित्र नहीं भेजना चाहते हैं, आप चाहते हैं कि आप संशोधित चित्र भेजें, इसलिए वे इतना बैंडविड्थ नहीं लेते हैं (और अपने मोबाइल एप्लिकेशन को तेज़ी से बनाने के लिए, आप अक्सर नहीं चाहते हैं इसे बिल्कुल आकार देने के लिए, आप वह छवि चाहते हैं जो आपके विचार में पूरी तरह फिट हो)। इस कारण से, अच्छे एप्लिकेशन क्लाउडिनरी जैसी चीज़ों का उपयोग कर रहे हैं (या हमारे पास आकार बदलने के लिए अपना स्वयं का छवि सर्वर है)।

इसके अलावा, यदि डेटा निजी नहीं है, तो आप एप्लिकेशन / बैकएंड को केवल URL पर वापस भेजते हैं और इसे सीधे क्लाउड स्टोरेज से डाउनलोड करते हैं, जो आपके सर्वर के लिए बैंडविड्थ और प्रसंस्करण समय की भारी बचत है। हमारे बड़े ऐप्स में हर महीने बहुत सारे टेराबाइट्स डाउनलोड होते हैं, आप इसे सीधे अपने प्रत्येक REST API सर्वर पर हैंडल नहीं करना चाहते हैं, जो CRUD ऑपरेशन पर केंद्रित है। आप इसे एक स्थान पर संभालना चाहते हैं (हमारी इमेजस्वर, जिसमें कैशिंग आदि हैं) या क्लाउड सेवाओं को संभालना चाहिए।


विपक्ष: एकमात्र "विपक्ष" जो आपको सोचना चाहिए "असाइन की गई छवियां नहीं हैं"। उपयोगकर्ता छवियों का चयन करता है और अन्य क्षेत्रों को भरने के साथ जारी रहता है, लेकिन फिर वह "नाह" कहता है और एप्लिकेशन या टैब को बंद कर देता है, लेकिन इस बीच आपने छवि को सफलतापूर्वक अपलोड कर दिया है। इसका मतलब है कि आपने एक छवि अपलोड की है जो कहीं भी असाइन नहीं की गई है।

इसे संभालने के कई तरीके हैं। सबसे आसान एक है "मुझे परवाह नहीं है", जो एक प्रासंगिक है, अगर यह बहुत बार नहीं हो रहा है या आपके पास हर छवि उपयोगकर्ता को स्टोर करने की इच्छा है जो आपको (किसी भी कारण से) भेजते हैं और आप कोई भी नहीं चाहते हैं विलोपन।

एक और आसान भी है - आपके पास हर सप्ताह CRON और यानी आप एक सप्ताह से अधिक पुरानी सभी अप्रकाशित छवियों को हटाते हैं।


क्या होगा यदि [जैसे ही आप छवि का चयन करते हैं, यह पृष्ठभूमि पर अपलोड करना शुरू कर देता है (आमतौर पर POST on / images समापन बिंदु), अपलोड करने के बाद आपको आईडी लौटा देता है] जब इंटरनेट कनेक्शन के कारण अनुरोध विफल हो गया? क्या आप उपयोगकर्ता को कुछ अन्य क्षेत्रों (जैसे पता, नाम, ...) के साथ आगे बढ़ने पर संकेत देंगे? मुझे यकीन है कि आप तब तक प्रतीक्षा करेंगे जब तक कि उपयोगकर्ता "भेजें" बटन को हिट न करें और आपके अनुरोध को पुन: प्रयास करें, स्क्रीन पर "अपलोडिंग ..." कहते हुए उन्हें प्रतीक्षा करें।
एड्रोमिल बलैस

5
@ AdromilBalais - RESTful API स्टेटलेस है, इसलिए यह कुछ भी नहीं करता है (सर्वर उपभोक्ता की स्थिति को ट्रैक नहीं करता है)। सेवा का उपभोक्ता (अर्थात वेब पेज या मोबाइल डिवाइस) विफल अनुरोधों को संभालने के लिए ज़िम्मेदार है, इसलिए उपभोक्ता को यह तय करना होगा कि क्या यह असफल होने के तुरंत बाद उसी अनुरोध को कॉल करता है या क्या करना है (अर्थात "छवि अपलोड विफल हुआ - फिर से कोशिश करना चाहता हूँ" ")
लिबीक

2
बहुत जानकारीपूर्ण और ज्ञानवर्धक उत्तर। जवाब के लिए धन्यवाद।
जुहैर ताहिर

यह वास्तव में प्रारंभिक समस्या को हल नहीं करता है। यह सिर्फ "क्लाउड सेवा का उपयोग करें" कहता है
मार्टिन मुजतको

3
@MartinMuzatko - यह करता है, यह दूसरा विकल्प चुनता है और आपको बताता है कि आपको इसका उपयोग कैसे करना चाहिए और क्यों करना चाहिए। यदि आपका मतलब है "लेकिन यह सही विकल्प नहीं है जो आपको एक अनुरोध में और निहितार्थ के बिना सब कुछ भेजने की अनुमति देता है" - हाँ, दुर्भाग्य से ऐसा कोई समाधान नहीं है।
कामवासना

104

कई निर्णय लेने हैं :

  1. संसाधन पथ के बारे में सबसे पहले :

    • छवि को अपने संसाधन के रूप में मॉडल करें:

      • उपयोगकर्ता (/ उपयोगकर्ता /: आईडी / छवि) में निहित: उपयोगकर्ता और छवि के बीच का संबंध अंतर्निहित है

      • रूट पथ (/ छवि) में:

        • ग्राहक को छवि और उपयोगकर्ता के बीच संबंध स्थापित करने के लिए जिम्मेदार ठहराया जाता है, या;

        • यदि छवि बनाने के लिए उपयोग किए जाने वाले POST अनुरोध के साथ एक सुरक्षा संदर्भ प्रदान किया जा रहा है, तो सर्वर प्रामाणिक उपयोगकर्ता और छवि के बीच संबंध स्थापित कर सकता है।

    • छवि को उपयोगकर्ता के भाग के रूप में एम्बेड करें

  2. दूसरा निर्णय छवि संसाधन का प्रतिनिधित्व करने के तरीके के बारे में है :

    • बेस 64 के रूप में JSON पेलोड को एन्कोड किया गया
    • मल्टीपार्ट पेलोड के रूप में

यह मेरा निर्णय ट्रैक होगा:

  • मैं आमतौर पर प्रदर्शन पर डिजाइन का पक्ष लेता हूं जब तक कि इसके लिए कोई मजबूत मामला न हो। यह सिस्टम को अधिक टिकाऊ बनाता है और इसे आसानी से इंटीग्रेटर्स द्वारा समझा जा सकता है।
  • इसलिए मेरा पहला विचार छवि संसाधन के एक बेस 64 प्रतिनिधित्व के लिए जाना है क्योंकि यह आपको सब कुछ JSON रखने देता है। यदि आपने यह विकल्प चुना है तो आप संसाधन पथ को अपनी इच्छानुसार मॉडल कर सकते हैं।
    • यदि उपयोगकर्ता और छवि के बीच संबंध 1 से 1 है, तो मैं छवि को एक विशेषता के रूप में मॉडल करने का पक्ष लूंगा, यदि दोनों डेटा सेट एक ही समय में अपडेट किए जाते हैं। किसी भी अन्य मामले में आप स्वतंत्र रूप से छवि को मॉडल करने के लिए या तो एक विशेषता के रूप में चुन सकते हैं, इसे PUT या PATCH के माध्यम से या एक अलग संसाधन के रूप में अपडेट कर सकते हैं।
  • यदि आप मल्टीपार्ट पेलोड चुनते हैं तो मुझे लगता है कि छवि को एक संसाधन के रूप में मॉडल करने के लिए मजबूर होना चाहिए, ताकि अन्य संसाधन, हमारे मामले में, उपयोगकर्ता संसाधन, छवि के लिए द्विआधारी प्रतिनिधित्व का उपयोग करने के निर्णय से प्रभावित न हों।

फिर सवाल आता है: क्या बेस 64 बनाम मल्टीपार्ट चुनने के बारे में कोई प्रदर्शन प्रभाव है? । हम सोच सकते हैं कि मल्टीपर्ट प्रारूप में डेटा का आदान-प्रदान अधिक कुशल होना चाहिए। लेकिन यह लेख दिखाता है कि आकार के संदर्भ में दोनों प्रतिनिधित्व कितने कम हैं।

मेरी पसंद Base64:

  • लगातार डिजाइन निर्णय
  • नगण्य प्रदर्शन प्रभाव
  • जैसा कि ब्राउज़र डेटा यूआरआई (बेस 64 एनकोडेड इमेज) को समझते हैं, अगर क्लाइंट एक ब्राउज़र है, तो इन्हें बदलने की कोई आवश्यकता नहीं है
  • मैं इस पर एक वोट नहीं डालूंगा कि यह एक विशेषता या स्टैंडअलोन संसाधन के रूप में है, यह आपकी समस्या डोमेन (जो मुझे नहीं पता) और आपकी व्यक्तिगत प्राथमिकता पर निर्भर करता है।

3
क्या हम प्रोटोबूफ आदि जैसे अन्य क्रमिक प्रोटोकॉल का उपयोग करके डेटा को एनकोड नहीं कर सकते हैं? मूल रूप से मैं यह समझने की कोशिश कर रहा हूं कि क्या आधार और एन्कोडिंग के साथ आने वाले आकार और प्रसंस्करण समय में वृद्धि को संबोधित करने के अन्य सरल तरीके हैं।
एंडी डफ्रेसने

1
बहुत उलझाने वाला जवाब। कदम से कदम दृष्टिकोण के लिए धन्यवाद। इसने मुझे आपकी बातों को बहुत बेहतर समझा।
ज़ुहैर ताहिर

13

आपका दूसरा समाधान शायद सबसे सही है। आपको HTTP युक्ति का उपयोग करना चाहिए और जिस तरह से उनका इरादा था उसे mimetypes और फ़ाइल के माध्यम से अपलोड करें multipart/form-data। जहाँ तक रिश्तों को संभालने की बात है, मैं इस प्रक्रिया का उपयोग करूँगा (यह ध्यान में रखते हुए कि मैं आपकी मान्यताओं या सिस्टम डिज़ाइन के बारे में शून्य जानता हूँ):

  1. POSTकरने के लिए /usersउपयोगकर्ता इकाई बनाने के लिए।
  2. POSTप्रतिमा जहाँ HTTP छवि के अनुसार प्रतिमा पुनः प्राप्त की जा सकती है /images, को सुनिश्चित करना Location
  3. PATCH, /users/carPhotoऔर इसे Locationचरण 2 के हेडर में दी गई फोटो की आईडी असाइन करें ।

1
मेरे पास "कैसे क्लाइंट एपीआई का उपयोग करेगा" का कोई प्रत्यक्ष नियंत्रण नहीं है ... इस की समस्या यह है कि "मृत" चित्र जो कुछ संसाधनों पर पैच नहीं किए गए हैं ...
libik

4
आमतौर पर जब आप दूसरा विकल्प चुनते हैं, तो पहले मीडिया तत्व को अपलोड करना पसंद करते हैं और ग्राहक को मीडिया पहचानकर्ता वापस करते हैं, फिर ग्राहक मीडिया पहचानकर्ता सहित इकाई डेटा भेज सकता है, ये दृष्टिकोण टूटी हुई संस्थाओं ओ बेमेल जानकारी से बचता है।
केलरमैन रिवरो

2

कोई आसान उपाय नहीं है। हर तरह से उनके पेशेवरों और विपक्ष हैं। लेकिन विहित तरीका पहले विकल्प का उपयोग कर रहा है multipart/form-data:। जैसा कि डब्ल्यू 3 सिफारिश गाइड कहता है

सामग्री प्रकार "मल्टीपार्ट / फॉर्म-डेटा" का उपयोग उन प्रपत्रों को प्रस्तुत करने के लिए किया जाना चाहिए जिनमें फाइलें, गैर-एएससीआईआई डेटा और बाइनरी डेटा शामिल हैं।

हम वास्तव में फॉर्म नहीं भेज रहे हैं, लेकिन निहित सिद्धांत अभी भी लागू होता है। आधार 64 को बाइनरी प्रतिनिधित्व के रूप में उपयोग करना गलत है, क्योंकि आप अपने लक्ष्य को पूरा करने के लिए गलत टूल का उपयोग कर रहे हैं, दूसरी ओर, दूसरा विकल्प आपके एपीआई क्लाइंट को आपकी एपीआई सेवा का उपभोग करने के लिए अधिक काम करने के लिए मजबूर करता है। एक आसान से उपभोग करने वाले एपीआई की आपूर्ति करने के लिए आपको सर्वर साइड में कड़ी मेहनत करनी चाहिए। पहला विकल्प डिबग करना आसान नहीं है, लेकिन जब आप इसे करते हैं, तो यह शायद कभी नहीं बदलता है।

का उपयोग multipart/form-dataकर आप REST / http दर्शन के साथ चिपके हुए हैं। आप इसी तरह के प्रश्न का उत्तर देख सकते हैं

एक अन्य विकल्प यदि विकल्पों को मिलाते हैं, तो आप मल्टीपार्ट / फॉर्म-डेटा का उपयोग कर सकते हैं, लेकिन हर मूल्य को अलग भेजने के बजाय, आप इसके अंदर json पेलोड के साथ पेलोड नामक मान भेज सकते हैं। (मैं ASP.NET WebAPI 2 और ठीक काम करता है) का उपयोग करके इस दृष्टिकोण की कोशिश की।


2
यह W3 अनुशंसा मार्गदर्शिका यहाँ अप्रासंगिक है, क्योंकि यह HTML 4 युक्ति के संदर्भ में है।
जोहान

1
बहुत सही .... "गैर एएससीआईआई-डेटा" को मल्टीपार्ट की आवश्यकता है? इक्कीसवीं सदी में? UTF-8 दुनिया में? बेशक जो आज के लिए एक हास्यास्पद सिफारिश है। मुझे आश्चर्य है कि HTML 4 दिनों में अस्तित्व में है, लेकिन कभी-कभी इंटरनेट का बुनियादी ढांचा बहुत धीमी गति से चलता है।
रे तोल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.