현재이 URL을 공개하는 REST 웹 서비스가 있습니다.
http : // server / data / media
사용자는 POST
다음 JSON을 사용할 수 있습니다 .
{
"Name": "Test",
"Latitude": 12.59817,
"Longitude": 52.12873
}
새 미디어 메타 데이터를 만들려면
이제 미디어 메타 데이터와 동시에 파일을 업로드 할 수있는 기능이 필요합니다. 가장 좋은 방법은 무엇입니까? 새로운 속성을 도입 file
하고 base64로 파일을 인코딩 할 수는 있지만 더 좋은 방법이 있는지 궁금합니다.
또한 사용하여 있습니다 multipart/form-data
HTML 양식을 보내 것이 무엇처럼,하지만 난 REST 웹 서비스를 사용하고 있는데 나는 경우 모든 가능한에서 JSON을 사용하여에 충실하고자합니다.
답변
나는 2 단계 접근법이 합리적인 해결책이라는 Greg에 동의하지만, 다른 방법으로 할 것입니다. 난 그럴거야:
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"
}
클라이언트는이 ContentUrl을 사용하고 파일 데이터로 PUT을 수행 할 수 있습니다.
이 방법의 좋은 점은 서버가 시작될 때 엄청난 양의 데이터로 무게가 줄어들 때 반환되는 URL이 더 많은 공간 / 용량을 가진 다른 서버를 가리킬 수 있다는 것입니다. 또는 대역폭이 문제인 경우 일종의 라운드 로빈 방식을 구현할 수 있습니다.
답변
전체 요청 본문을 JSON으로 래핑하지 않기 때문에 multipart/form-data
단일 요청으로 JSON과 파일을 모두 게시하는 데 사용 하는 것이 충분하지 않다는 의미는 아닙니다 .
curl -F "metadata=<metadata.json" -F "file=@my-file.tar.gz" http://example.com/add-file
서버 측에서 (의사 코드에 Python 사용) :
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']
모든 파일을 포함하는 문자열이 될 것이며, 자신을 파싱해야합니다. 어떻게해야할지 확실하지 않지만, 어렵지 않거나 이전 방법을 사용하는 것이 좋습니다.
의 차이 @
와는 <
즉 @
, 반면에 파일이 업로드 파일로 첨부하려면 원인 <
텍스트 필드로 파일의 첨부합니다 내용.
추신 : 요청 curl
을 생성하는 방법으로 사용 POST
한다고해서 정확히 같은 HTTP 요청을 Python과 같은 프로그래밍 언어에서 보내거나 충분한 기능을 갖춘 도구를 사용하여 전송할 수는 없습니다.
답변
문제에 접근하는 한 가지 방법은 업로드를 2 단계 프로세스로 만드는 것입니다. 먼저 POST를 사용하여 파일 자체를 업로드합니다. 여기서 서버는 일부 식별자를 클라이언트에 반환합니다 (식별자는 파일 내용의 SHA1 일 수 있음). 그런 다음 두 번째 요청은 메타 데이터를 파일 데이터와 연관시킵니다.
{
"Name": "Test",
"Latitude": 12.59817,
"Longitude": 52.12873,
"ContentID": "7a788f56fa49ae0ba5ebde780efe4d6a89b5db47"
}
JSON 요청 자체로 인코딩 된 파일 데이터베이스 base64를 포함하면 전송되는 데이터 크기가 33 % 증가합니다. 파일의 전체 크기에 따라 중요하거나 중요하지 않을 수 있습니다.
다른 방법은 원시 파일 데이터의 POST를 사용하지만 HTTP 요청 헤더에 메타 데이터를 포함시키는 것입니다. 그러나 이것은 기본 REST 작업과 약간 다르며 일부 HTTP 클라이언트 라이브러리에서는 더 어색 할 수 있습니다.
답변
나는 이것이 매우 오래된 질문이라는 것을 알고 있지만, 내가이 게시물을 방문했을 때 같은 것을 찾는 다른 누군가를 도울 수 있기를 바랍니다. 메타 데이터가 Guid and int라는 비슷한 문제가있었습니다. 솔루션은 동일합니다. 필요한 메타 데이터를 URL의 일부로 만들 수 있습니다.
“Controller”클래스의 POST 수락 메소드 :
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 (HttpConfiguration config)가 필요합니다.
config.Routes.MapHttpRoute(
name: "FooController",
routeTemplate: "api/{controller}/{name}/{latitude}/{longitude}",
defaults: new { }
);
답변
파일과 메타 데이터가 하나의 리소스를 만드는 경우 한 번의 요청으로 둘 다 업로드해도 좋습니다. 샘플 요청은 다음과 같습니다.
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--
답변
8 년 동안 왜 아무도 쉬운 답변을 게시하지 않았는지 이해가되지 않습니다. 파일을 base64로 인코딩하는 대신 json을 문자열로 인코딩하십시오. 그런 다음 서버 측에서 json을 디코딩하십시오.
자바 스크립트에서 :
let formData = new FormData();
formData.append("file", myfile);
formData.append("myjson", JSON.stringify(myJsonObject));
Content-Type을 사용하여 POST : multipart / form-data
서버 측에서 파일을 정상적으로 검색하고 json을 문자열로 검색하십시오. 문자열을 객체로 변환하십시오. 일반적으로 사용하는 프로그래밍 언어에 관계없이 한 줄의 코드입니다.
(예, 잘 작동합니다. 내 앱 중 하나에서 수행하고 있습니다.)