혼합 데이터 및 파일 전송에 멀티 파트 / 폼 데이터를 사용하는 이유는 무엇입니까?


14

나는 C #에서 일하고 있고 내가 쓰고있는 두 응용 프로그램 사이에서 약간의 의사 소통을하고 있습니다. 웹 API와 JSON이 마음에 들었습니다. 이제 텍스트 데이터와 파일이 포함 된 두 서버 사이에 레코드를 보내기 위해 루틴을 작성하는 시점에 있습니다.

인터넷에 따르면 다음과 같이 multipart / form-data 요청을 사용해야합니다.

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 직렬화 및 역 직렬화를 사용할 수 있습니다. 또한이 데이터를 보내는 코드는 매우 간단합니다. 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);
}

각 항목에 대해 더 이상 바보 구분 기호와 헤더가 없습니다. 이제 남은 질문은 성능입니다. 그래서 나는 그것을 프로파일했다. 50KB에서 1.5MB 정도의 전선을 통해 전송 해야하는 50 개의 샘플 파일 세트가 있습니다. 먼저 파일에서 바이트 배열로 스트리밍하여 파일에서 스트리밍되는 논리와 비교하여 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

그 결과 단순 읽기는 항상 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 자에 불과하기 때문에 최적화 된 알고리즘이 훨씬 더 나은 것처럼 보이지는 않습니다. 어쨌든 3 배 더 좋지는 않습니다. 이는 파일 바이트를 구분 기호로 검사하는 대신 Base64 인코딩을 수행하는 성능 이점입니다.

분명히 Base64 인코딩은 첫 번째 테이블에 표시된 것처럼 크기를 늘리지 만 유니 코드 가능 UTF-8에서도 그렇게 나쁘지는 않으며 원하는 경우 잘 압축됩니다. 그러나 실제 이점은 내 코드가 훌륭하고 깨끗하며 쉽게 이해할 수 있으며 JSON 요청 페이로드를 많이 보더라도 시력을 손상시키지 않는다는 것입니다.

그렇다면 왜 지구상에서 multipart / form-data를 사용하는 대신 단순히 Base64로 JSON으로 파일을 인코딩하지 않는 사람이 있습니까? 표준이 있지만 이러한 표준은 상대적으로 자주 변경됩니다. 어쨌든 표준은 실제로 제안 일 뿐입니 까?

답변:


16

multipart/form-dataHTML 양식을 위해 생성 된 구문입니다. 긍정적 인 점 multipart/form-data은 전송 크기가 전송되는 객체의 크기에 가깝다는 것입니다. 객체의 텍스트 인코딩에서 크기가 크게 팽창합니다. 인터넷 대역폭은 프로토콜이 발명되었을 때 CPU 사이클보다 더 중요한 상품이라는 것을 이해할 수 있습니다.

인터넷에 따르면 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.