আমি কীভাবে কোনও আরএসটি ওয়েব পরিষেবা ব্যবহার করে মেটাডেটা যুক্ত ফাইল আপলোড করব?


249

আমার কাছে একটি REST ওয়েব পরিষেবা রয়েছে যা বর্তমানে এই URL টি প্রকাশ করে:

HTTP: // সার্ভার / ডেটা / মিডিয়া

যেখানে ব্যবহারকারীরা POSTনিম্নলিখিত JSON করতে পারেন :

{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873
}

একটি নতুন মিডিয়া মেটাডেটা তৈরি করতে।

এখন আমার মিডিয়া মেটাডেটা হিসাবে একই সাথে একটি ফাইল আপলোড করার ক্ষমতা প্রয়োজন। এটি সম্পর্কে সবচেয়ে ভাল উপায় কি? আমি একটি নতুন সম্পত্তি পরিচিত fileএবং বেস 64 ফাইলটি এনকোডের সাথে পরিচয় করিয়ে দিতে পারি , তবে আমি আরও ভাবছিলাম যে এর থেকে আরও ভাল উপায় আছে কিনা।

multipart/form-dataএইচটিএমএল ফর্ম যা পাঠিয়ে দেবে তার মতো ব্যবহারও রয়েছে তবে আমি একটি আরএসটি ওয়েব পরিষেবা ব্যবহার করছি এবং আমি যদি সম্ভব হয় তবে জেএসওএন ব্যবহার করে যেতে চাই।


35
কেবলমাত্র জেএসএন ব্যবহার করে আটকানো সত্যই একটি রিস্টাল ওয়েব পরিষেবা থাকা প্রয়োজন। আরআরএসটি মূলত এমন কিছু যা HTTP পদ্ধতিগুলির মূল নীতিগুলি এবং কিছু অন্যান্য (যুক্তিযুক্তভাবে মানহীন) নিয়ম অনুসরণ করে।
এরিক কাপলুন

উত্তর:


192

আমি গ্রেগের সাথে একমত যে দুটি দফার পন্থা একটি যুক্তিসঙ্গত সমাধান, তবে আমি অন্য উপায়ে এটি করতাম। আমি করবো:

POST http://server/data/media
body:
{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873
}

মেটাডেটা এন্ট্রি তৈরি করতে এবং প্রতিক্রিয়া যেমন:

201 Created
Location: http://server/data/media/21323
{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873,
    "ContentUrl": "http://server/data/media/21323/content"
}

ক্লায়েন্ট তারপরে এই কন্টেন্টআরলটি ব্যবহার করতে পারে এবং ফাইল ডেটা দিয়ে একটি পুট করতে পারে।

এই পদ্ধতির সম্পর্কে দুর্দান্ত জিনিসটি যখন আপনার সার্ভারটি প্রচুর পরিমাণে ডেটা দিয়ে ভার করা শুরু করে, আপনি যে ইউআরএল ফিরে আসেন তা আরও স্থান / ক্ষমতা সহ অন্য কোনও সার্ভারে নির্দেশ করতে পারে। বা ব্যান্ডউইথ যদি কোনও সমস্যা হয় তবে আপনি কোনও ধরণের রাউন্ড রবিন পদ্ধতির প্রয়োগ করতে পারেন।


8
প্রথমে সামগ্রীটি প্রেরণের একটি সুবিধা হ'ল মেটাটাটা উপস্থিত হওয়ার সাথে সাথে সামগ্রীটি ইতিমধ্যে উপস্থিত রয়েছে। শেষ পর্যন্ত সঠিক উত্তরটি সিস্টেমের ডেটাগুলির সংস্থার উপর নির্ভর করে।
গ্রেগ হিউগিল

ধন্যবাদ, আমি এটিকে সঠিক উত্তর হিসাবে চিহ্নিত করেছি কারণ এটিই আমি করতে চেয়েছিলাম। দুর্ভাগ্যক্রমে, একটি অদ্ভুত ব্যবসায়িক নিয়মের কারণে, আমাদের আপলোডটিকে কোনও ক্রমে (মেটাসাটা প্রথমে বা ফাইল আগে ফাইল) করতে দেওয়া উচিত। আমি ভাবছিলাম যে উভয় পরিস্থিতি মোকাবিলার মাথাব্যথা বাঁচানোর জন্য দু'জনের একত্র করার কোনও উপায় ছিল কিনা?
ড্যানিয়েল টি।

@ ড্যানিয়েল যদি আপনি প্রথমে ডেটা ফাইল পোস্ট করেন তবে আপনি স্থানে ফিরে আসা ইউআরএল নিতে পারেন এবং এটি মেটাডেটার কন্টেন্টআরল বৈশিষ্ট্যে যুক্ত করতে পারেন। এইভাবে, সার্ভারটি যখন মেটাডেটাটি গ্রহণ করে, যদি কোনও বিষয়বস্তু বিদ্যমান থাকে তবে ফাইলটি কোথায় তা এটি ইতিমধ্যে জানে। যদি কোনও কন্টেন্টআরল না থাকে, তবে এটি জানে যে এটির একটি তৈরি করা উচিত।
ড্যারেল মিলার 21

আপনি যদি প্রথমে পোষ্টটি করেন, আপনি কি একই ইউআরএল পোস্ট করবেন? (/ সার্ভার / ডেটা / মিডিয়া) বা আপনি ফাইল-প্রথম আপলোডগুলির জন্য অন্য এন্ট্রি পয়েন্ট তৈরি করবেন?
ম্যাট ব্রিলসফোর্ড

1
@ ফ্যারাওয়ে যদি মেটাডেটাতে কোনও চিত্রের "পছন্দ" সংখ্যাটি অন্তর্ভুক্ত থাকে তবে কী হবে? আপনি কি তখন এটি একটি একক সংস্থান হিসাবে বিবেচনা করবেন? বা আরও স্পষ্টতই, আপনি কি পরামর্শ দিচ্ছেন যে আমি যদি কোনও চিত্রের বর্ণনাকে সম্পাদনা করতে চাই, তবে আমাকে ছবিটি পুনরায় আপলোড করতে হবে? অনেকগুলি ক্ষেত্রে রয়েছে যেখানে বহু অংশের ফর্মগুলি সঠিক সমাধান the এটা সবসময় ক্ষেত্রে হয় না।
ড্যারেল মিলার 26'18

103

কেবল আপনি JSON- এ পুরো অনুরোধের বডিটি মুড়ে রাখছেন না, এর অর্থ এই নয় যে multipart/form-dataকোনও একক অনুরোধে JSON এবং ফাইল (গুলি) উভয়ই পোস্ট করা ব্যবহার করা বিশুদ্ধ নয় :

curl -F "metadata=<metadata.json" -F "file=@my-file.tar.gz" http://example.com/add-file

সার্ভার সাইডে (সিউডোকোডের জন্য পাইথন ব্যবহার করে):

class AddFileResource(Resource):
    def render_POST(self, request):
        metadata = json.loads(request.args['metadata'][0])
        file_body = request.args['file'][0]
        ...

একাধিক ফাইল আপলোড করতে, প্রতিটি জন্য পৃথক "ফর্ম ক্ষেত্র" ব্যবহার করা সম্ভব:

curl -F "metadata=<metadata.json" -F "file1=@some-file.tar.gz" -F "file2=@some-other-file.tar.gz" http://example.com/add-file

... যে ক্ষেত্রে সার্ভার কোড থাকবে request.args['file1'][0]এবংrequest.args['file2'][0]

বা অনেকের জন্য একইটিকে পুনরায় ব্যবহার করুন:

curl -F "metadata=<metadata.json" -F "files=@some-file.tar.gz" -F "files=@some-other-file.tar.gz" http://example.com/add-file

... যে ক্ষেত্রে request.args['files']কেবল দৈর্ঘ্যের 2 তালিকা হবে।

বা একক ক্ষেত্রের মাধ্যমে একাধিক ফাইল পাস করুন:

curl -F "metadata=<metadata.json" -F "files=@some-file.tar.gz,some-other-file.tar.gz" http://example.com/add-file

... এই ক্ষেত্রে request.args['files']সমস্ত ফাইল যুক্ত একটি স্ট্রিং হবে, যা আপনাকে নিজের বিশ্লেষণ করতে হবে - কীভাবে করবেন তা নিশ্চিত নন, তবে আমি নিশ্চিত যে এটি কঠিন নয়, বা পূর্ববর্তী পন্থাগুলি ভাল ব্যবহার করুন use

@এবং এর মধ্যে পার্থক্য <হ'ল @ফাইলটি একটি ফাইল আপলোড হিসাবে সংযুক্ত হয়ে যায়, যেখানে <ফাইলের সামগ্রীগুলি একটি পাঠ্য ক্ষেত্র হিসাবে সংযুক্ত করে।

পিএস ঠিক এই কারণে যে আমি অনুরোধগুলি curlউত্পন্ন করার উপায় হিসাবে ব্যবহার করছি POSTতার অর্থ এই নয় যে পাইথনের মতো প্রোগ্রামিং ভাষা থেকে ঠিক একই এইচটিটিপি অনুরোধগুলি প্রেরণ করা যায়নি বা কোনও যথেষ্ট সক্ষম সরঞ্জাম ব্যবহার করা যায় না।


4
আমি নিজেই এই পদ্ধতির বিষয়ে ভাবছিলাম এবং কেন আমি অন্য কাউকে এখনও এটি প্রকাশ করতে দেখিনি। আমি সম্মত, আমার কাছে পুরোপুরি রেস্টস্টফুল বলে মনে হচ্ছে।
স্যুপডগ

1
হ্যাঁ! এটি অত্যন্ত ব্যবহারিক পদ্ধতির এবং পুরো অনুরোধের জন্য সামগ্রীর ধরণ হিসাবে "অ্যাপ্লিকেশন / জেসন" ব্যবহার করার চেয়ে এটি কোনও কম বিশ্রামজনক নয়।
সিলিল

.. তবে এটি কেবল তখনই সম্ভব যদি আপনার কাছে একটি জেএসন ফাইলে ডেটা থাকে এবং এটি আপলোড হয়, যা এরকম নয়
Itjavi

5
@ এমজলনিক আপনার মন্তব্য অপ্রাসঙ্গিক: সিআরএল উদাহরণগুলি কেবলমাত্র, ভাল উদাহরণ ; উত্তরে স্পষ্টতই বলা আছে যে আপনি অনুরোধটি প্রেরণ করতে যে কোনও কিছু ব্যবহার করতে পারেন ... এছাড়াও, কী আপনাকে কেবল লেখাগুলি থেকে বাধা দেয় curl -f 'metadata={"foo": "bar"}'?
এরিক কাপলুন

3
আমি এই পদ্ধতির ব্যবহার করছি কারণ আমি যে অ্যাপ্লিকেশনটি বিকাশ করছি তার জন্য গৃহীত উত্তরগুলি কাজ করবে না (ফাইলটি ডেটার আগে উপস্থিত থাকতে পারে না এবং এটি ডেটা আগে আপলোড করা হয় এবং ফাইলটি কখনও আপলোড হয় না এমন ক্ষেত্রে পরিচালনা করতে অপ্রয়োজনীয় জটিলতা যুক্ত করে) ।
বিটসভলভ

33

সমস্যাটির কাছে যাওয়ার একটি উপায় হ'ল আপলোডটিকে একটি দুটি পর্যায়ের প্রক্রিয়া করা। প্রথমত, আপনি নিজের পোস্টটি ব্যবহার করে নিজেই ফাইল আপলোড করবেন, যেখানে সার্ভার ক্লায়েন্টকে কিছু শনাক্তকারীকে ফিরিয়ে দেয় (কোনও সনাক্তকারী ফাইলের সামগ্রীর SHA1 হতে পারে)। তারপরে, দ্বিতীয় অনুরোধটি ফাইল ডেটার সাথে মেটাডেটা সংযুক্ত করে:

{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873,
    "ContentID": "7a788f56fa49ae0ba5ebde780efe4d6a89b5db47"
}

JSON অনুরোধে এনকোড থাকা ফাইল ডেটা বেস 64 সহ নিজেই স্থানান্তরিত ডেটার আকার 33% বাড়িয়ে তুলবে। ফাইলের সামগ্রিক আকারের উপর নির্ভর করে এটি গুরুত্বপূর্ণ বা নাও হতে পারে।

আর একটি পদ্ধতি হতে পারে কাঁচা ফাইল ডেটার একটি পোষ্ট ব্যবহার করা, তবে HTTP অনুরোধ শিরোনামে কোনও মেটাডেটা অন্তর্ভুক্ত করা উচিত। তবে এটি বেসিক আরএসটি অপারেশনের বাইরে কিছুটা পড়ে এবং কিছু এইচটিটিপি ক্লায়েন্ট লাইব্রেরির জন্য আরও বিশ্রী হতে পারে।


আপনি মাত্র 1/4 দ্বারা Ascii85 বাড়িয়ে ব্যবহার করতে পারেন।
সিঙ্গাগল্ল

বেস 64 কেন আকারটি এত বাড়িয়ে দেয় তার কোনও রেফারেন্স?
জাম01

1
@ জাম01: কাকতালীয়ভাবে, আমি গতকাল সবেমাত্র এমন কিছু দেখেছি যা স্পেস প্রশ্নের উত্তরের জবাব দেয়: বেস 64 এনকোডিংয়ের স্পেস ওভারহেড কী?
গ্রেগ হিউগিল

10

আমি বুঝতে পেরেছি এটি একটি খুব পুরানো প্রশ্ন, তবে আশা করি এটি একই জিনিসটির সন্ধানে এই পোস্টে আসার সাথে সাথে এটি অন্য কাউকে সাহায্য করবে। আমার অনুরূপ সমস্যা ছিল, কেবল আমার মেটাডেটা হ'ল গাইড এবং অন্তর্নিহিত। সমাধান যদিও একই। আপনি কেবল প্রয়োজনীয় মেটাডেটা ইউআরএলের অংশ হিসাবে তৈরি করতে পারেন।

আপনার "নিয়ামক" শ্রেণিতে পোষ্ট গ্রহণের পদ্ধতি:

public Task<HttpResponseMessage> PostFile(string name, float latitude, float longitude)
{
    //See http://stackoverflow.com/a/10327789/431906 for how to accept a file
    return null;
}

তারপরে আপনি যে কোনও রুট নিবন্ধভুক্ত করছেন, আমার ক্ষেত্রে WebApiConfig.Register (এইচটিপিপি কনফিগারেশন কনফিগারেশন)।

config.Routes.MapHttpRoute(
    name: "FooController",
    routeTemplate: "api/{controller}/{name}/{latitude}/{longitude}",
    defaults: new { }
);

5

যদি আপনার ফাইল এবং এর মেটাডেটা একটি উত্স তৈরি করে, তবে উভয়কেই একটি অনুরোধে আপলোড করা পুরোপুরি ঠিক। নমুনা অনুরোধটি হ'ল:

POST https://target.com/myresources/resourcename HTTP/1.1

Accept: application/json

Content-Type: multipart/form-data; 

boundary=-----------------------------28947758029299

Host: target.com

-------------------------------28947758029299

Content-Disposition: form-data; name="application/json"

{"markers": [
        {
            "point":new GLatLng(40.266044,-74.718479), 
            "homeTeam":"Lawrence Library",
            "awayTeam":"LUGip",
            "markerImage":"images/red.png",
            "information": "Linux users group meets second Wednesday of each month.",
            "fixture":"Wednesday 7pm",
            "capacity":"",
            "previousScore":""
        },
        {
            "point":new GLatLng(40.211600,-74.695702),
            "homeTeam":"Hamilton Library",
            "awayTeam":"LUGip HW SIG",
            "markerImage":"images/white.png",
            "information": "Linux users can meet the first Tuesday of the month to work out harward and configuration issues.",
            "fixture":"Tuesday 7pm",
            "capacity":"",
            "tv":""
        },
        {
            "point":new GLatLng(40.294535,-74.682012),
            "homeTeam":"Applebees",
            "awayTeam":"After LUPip Mtg Spot",
            "markerImage":"images/newcastle.png",
            "information": "Some of us go there after the main LUGip meeting, drink brews, and talk.",
            "fixture":"Wednesday whenever",
            "capacity":"2 to 4 pints",
            "tv":""
        },
] }

-------------------------------28947758029299

Content-Disposition: form-data; name="name"; filename="myfilename.pdf"

Content-Type: application/octet-stream

%PDF-1.4
%
2 0 obj
<</Length 57/Filter/FlateDecode>>stream
x+r
26S00SI2P0Qn
F
!i\
)%!Y0i@.k
[
endstream
endobj
4 0 obj
<</Type/Page/MediaBox[0 0 595 842]/Resources<</Font<</F1 1 0 R>>>>/Contents 2 0 R/Parent 3 0 R>>
endobj
1 0 obj
<</Type/Font/Subtype/Type1/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
endobj
3 0 obj
<</Type/Pages/Count 1/Kids[4 0 R]>>
endobj
5 0 obj
<</Type/Catalog/Pages 3 0 R>>
endobj
6 0 obj
<</Producer(iTextSharp 5.5.11 2000-2017 iText Group NV \(AGPL-version\))/CreationDate(D:20170630120636+02'00')/ModDate(D:20170630120636+02'00')>>
endobj
xref
0 7
0000000000 65535 f 
0000000250 00000 n 
0000000015 00000 n 
0000000338 00000 n 
0000000138 00000 n 
0000000389 00000 n 
0000000434 00000 n 
trailer
<</Size 7/Root 5 0 R/Info 6 0 R/ID [<c7c34272c2e618698de73f4e1a65a1b5><c7c34272c2e618698de73f4e1a65a1b5>]>>
%iText-5.5.11
startxref
597
%%EOF

-------------------------------28947758029299--

3

আমি বুঝতে পারছি না, আট বছর ধরে কেন কেউ সহজ উত্তর পোস্ট করেনি। বেস 64 হিসাবে ফাইলটি এনকোড করার পরিবর্তে স্ট্রিং হিসাবে জসনকে এনকোড করুন। তারপরে সার্ভারের পাশের জসনটি ডিকোড করুন।

জাভাস্ক্রিপ্টে:

let formData = new FormData();
formData.append("file", myfile);
formData.append("myjson", JSON.stringify(myJsonObject));

বিষয়বস্তুর ধরণ ব্যবহার করে এটি পোস্ট করুন: গুণিত / ফর্ম-ডেটা

সার্ভারের দিকে, ফাইলটি সাধারণত পুনরুদ্ধার করুন এবং স্ট্রিং হিসাবে জেসন পুনরুদ্ধার করুন। স্ট্রিংটিকে কোনও অবজেক্টে রূপান্তর করুন, যা সাধারণত কোডের এক লাইন হয় আপনি কোন প্রোগ্রামিং ভাষা ব্যবহার করেন না কেন।

(হ্যাঁ, এটি দুর্দান্ত কাজ করে my এটি আমার অ্যাপ্লিকেশনগুলির একটিতে করছেন))

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.