파일이 첨부 된 간단한 양식을 제출하면 :
<form enctype="multipart/form-data" action="http://localhost:3000/upload?upload_progress_id=12344" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
파일을 내부적으로 어떻게 보냅니 까? 파일이 HTTP 본문의 일부로 데이터로 전송됩니까? 이 요청의 헤더에는 파일 이름과 관련된 내용이 없습니다.
파일을 보낼 때 HTTP의 내부 작동을 알고 싶습니다.
답변
파일을 선택하고 양식을 제출할 때 어떤 일이 발생하는지 살펴 보겠습니다 (간단하게 헤더를 자른 것입니다).
POST /upload?upload_progress_id=12344 HTTP/1.1
Host: localhost:3000
Content-Length: 1325
Origin: http://localhost:3000
... other headers ...
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryePkpFF7tjBAqx29L
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="MAX_FILE_SIZE"
100000
------WebKitFormBoundaryePkpFF7tjBAqx29L
Content-Disposition: form-data; name="uploadedfile"; filename="hello.o"
Content-Type: application/x-object
... contents of file goes here ...
------WebKitFormBoundaryePkpFF7tjBAqx29L--
참고 : --
마지막 경계 문자열의 끝에서와 같이 각 경계 문자열에는 접두사가 추가되어야 합니다. 위의 예는 이미 이것을 포함하고 있지만 놓치기 쉽습니다. 아래 @Andreas의 코멘트를 참조하십시오.
양식 매개 변수를 URL 인코딩하는 대신 양식 매개 변수 (파일 데이터 포함)는 요청 본문의 여러 부분으로 된 문서에서 섹션으로 전송됩니다.
위의 예에서는 MAX_FILE_SIZE
파일 데이터가 포함 된 섹션뿐만 아니라 양식에 설정된 값으로 입력 을 볼 수 있습니다 . 파일 이름은 Content-Disposition
헤더의 일부입니다 .
자세한 내용은 여기에 있습니다 .
답변
파일을 내부적으로 어떻게 보냅니 까?
형식은 호출 multipart/form-data
에서 요청과 같은 : 무엇에 enctype = ‘다중 / 폼 데이터’는 뜻입니까?
할거다:
- HTML5 참조를 더 추가하십시오.
- 설명 왜 그가 양식을 제출 예와 권리
HTML5 참조
다음과 같은 세 가지 가능성 이 있습니다 enctype
.
x-www-urlencoded
multipart/form-data
(사양은 RFC2388 을 가리킴 )text-plain
. 이것은 “컴퓨터로 확실하게 해석 할 수 없음”이므로 프로덕션 환경에서는 절대 사용해서는 안되며 더 이상 조사하지 않을 것입니다.
예제를 생성하는 방법
각 방법의 예를 보면 각 방법의 작동 방식과 사용 방법이 명확 해집니다.
다음을 사용하여 예제를 생성 할 수 있습니다.
nc -l
또는 ECHO 서버 : GET / POST 요청을 승인하는 HTTP 테스트 서버- 브라우저 나 cURL과 같은 사용자 에이전트
양식을 최소 .html
파일 로 저장하십시오 .
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
<p><input type="text" name="text1" value="text default">
<p><input type="text" name="text2" value="aωb">
<p><input type="file" name="file1">
<p><input type="file" name="file2">
<p><input type="file" name="file3">
<p><button type="submit">Submit</button>
</form>
</body>
</html>
우리의 기본 텍스트 값 설정 aωb
수단 aωb
때문 ω
이다 U+03C9
바이트있는, 61 CF 89 62
UTF-8인치
업로드 할 파일을 작성하십시오.
echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary
작은 에코 서버를 실행하십시오.
while true; do printf '' | nc -l 8000 localhost; done
브라우저에서 HTML을 열고 파일을 선택한 후 제출을 클릭하고 터미널을 확인하십시오.
nc
받은 요청을 인쇄합니다.
테스트 대상 : Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
멀티 파트 / 폼 데이터
Firefox가 보냈습니다 :
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
이진 파일 및 텍스트 필드의 경우 바이트 61 CF 89 62
( aωb
UTF-8)가 문자 그대로 전송됩니다. nc -l localhost 8000 | hd
를 사용하여 바이트를 확인할 수 있습니다 .
61 CF 89 62
전송되었습니다 ( 61
== ‘a’및 62
== ‘b’).
따라서 다음 사항이 분명합니다.
-
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
컨텐츠 유형을로 설정하고multipart/form-data
필드가 주어진boundary
문자열 로 구분된다고 말합니다 .그러나 다음 사항에 유의하십시오.
boundary=---------------------------735323031399963166993862150
--
실제 장벽보다 덜 두껍 습니다.-----------------------------735323031399963166993862150
표준에 경계가 두 개의 대시로 시작해야하기 때문
--
입니다. 다른 대시는 Firefox가 임의의 경계를 구현하기로 선택한 방식으로 보입니다. RFC 7578은 다음 두 개의 대시--
가 필요하다고 분명히 언급 합니다.4.1. multipart / form-data의 “경계”매개 변수
다른 다중 부품 유형과 마찬가지로 부품은 CRLF, “-“및 “boundary”매개 변수의 값을 사용하여 구성된 경계 구분 기호로 구분됩니다.
-
모든 필드는 데이터 전에 일부 서브 헤더를 가져옵니다
Content-Disposition: form-data;
필드name
의filename
데이터 다음을.서버는 다음 경계 문자열까지 데이터를 읽습니다. 브라우저는 어떤 필드에도 나타나지 않는 경계를 선택해야하므로 요청마다 경계가 다를 수 있습니다.
고유 경계가 있으므로 데이터 인코딩이 필요하지 않습니다. 이진 데이터는 그대로 전송됩니다.
TODO : 최적의 경계 크기 (
log(N)
내기)와 그것을 찾는 알고리즘의 이름 / 실행 시간은 얼마입니까? 질문 : /cs/39687/find-the-shortest-sequence-that-is-not-a-sub-sequence-of-a-set-of-sequences -
Content-Type
브라우저에 의해 자동으로 결정됩니다.정확하게 결정된 방법 : 업로드 된 파일의 MIME 유형은 브라우저에 의해 어떻게 결정됩니까?
application / x-www-form-urlencoded
이제 변경 enctype
에를 application/x-www-form-urlencoded
, 브라우저, 그리고 다시 보내기를 다시로드합니다.
Firefox가 보냈습니다 :
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
분명히 파일 데이터는 전송되지 않았고 기본 이름 만 전송되었습니다. 따라서 파일에는 사용할 수 없습니다.
텍스트 필드에 관해서는, 우리는 같은 것을 보통의 인쇄 가능한 문자를 참조 a
와 b
같은 인쇄 할 수없는 것들 동안 1 바이트에 보내졌다 0xCF
하고 0x89
위로했다 3 바이트 각 : %CF%89
!
비교
파일 업로드는 종종 인쇄 할 수없는 많은 문자 (예 : 이미지)를 포함하지만 텍스트 형식은 거의 없습니다.
예제에서 우리는 다음을 보았습니다.
-
multipart/form-data
: 메시지에 몇 바이트의 경계 오버 헤드를 추가하고 계산하는 데 시간이 걸리지 만 각 바이트를 1 바이트로 보냅니다. -
application/x-www-form-urlencoded
: 필드 당 단일 바이트 경계 (&
)를 갖지만 인쇄 할 수없는 모든 문자에 대해 3 배 의 선형 오버 헤드 계수를 추가합니다 .
따라서로 파일을 보낼 수 있어도 application/x-www-form-urlencoded
비효율적이므로 원하지 않습니다.
그러나 텍스트 필드에있는 인쇄 가능한 문자의 경우 중요하지 않으며 오버 헤드가 적으므로 그냥 사용하십시오.
답변
이진 콘텐츠로 파일 보내기 (양식 또는 FormData없이 업로드)
주어진 답변 / 예에서 파일은 HTML 양식으로 또는 FormData API를 사용하여 업로드 될 가능성이 높습니다 . 파일은 요청에서 전송 된 데이터의 일부일 뿐이므로 multipart/form-data
Content-Type
헤더입니다.
파일을 유일한 컨텐츠로 보내려면 요청 본문으로 직접 추가하고 Content-Type
헤더를 전송중인 파일의 MIME 유형으로 설정할 수 있습니다. Content-Disposition
헤더 에 파일 이름을 추가 할 수 있습니다 . 다음과 같이 업로드 할 수 있습니다.
var xmlHttpRequest = new XMLHttpRequest();
var file = ...file handle...
var fileName = ...file name...
var target = ...target...
var mimeType = ...mime type...
xmlHttpRequest.open('POST', target, true);
xmlHttpRequest.setRequestHeader('Content-Type', mimeType);
xmlHttpRequest.setRequestHeader('Content-Disposition', 'attachment; filename="' + fileName + '"');
xmlHttpRequest.send(file);
양식을 사용하지 않으려는 경우 하나의 단일 파일 만 업로드하려는 경우 요청에 파일을 포함시키는 가장 쉬운 방법입니다.
답변
이 샘플 Java 코드가 있습니다.
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class TestClass {
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(8081);
Socket accept = socket.accept();
InputStream inputStream = accept.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
char readChar;
while ((readChar = (char) inputStreamReader.read()) != -1) {
System.out.print(readChar);
}
inputStream.close();
accept.close();
System.exit(1);
}
}
이 test.html 파일이 있습니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>File Upload!</title>
</head>
<body>
<form method="post" action="http://localhost:8081" enctype="multipart/form-data">
<input type="file" name="file" id="file">
<input type="submit">
</form>
</body>
</html>
마지막으로 테스트 목적으로 사용할 파일 a.dat 라는 이름 은 다음과 같습니다.
0x39 0x69 0x65
위의 바이트를 ASCII 또는 UTF-8 문자로 해석하면 실제로 다음을 나타냅니다.
9ie
Java 코드를 실행하고 즐겨 사용하는 브라우저에서 test.html 을 열고 a.dat
양식을 업로드 하고 제출 한 다음 서버가받는 내용을 확인하십시오.
POST / HTTP/1.1
Host: localhost:8081
Connection: keep-alive
Content-Length: 196
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: null
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.97 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary06f6g54NVbSieT6y
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en,en-US;q=0.8,tr;q=0.6
Cookie: JSESSIONID=27D0A0637A0449CF65B3CB20F40048AF
------WebKitFormBoundary06f6g54NVbSieT6y
Content-Disposition: form-data; name="file"; filename="a.dat"
Content-Type: application/octet-stream
9ie
------WebKitFormBoundary06f6g54NVbSieT6y--
Java에 문자를 UTF-8 문자로 처리하도록 인쇄하도록 지시했기 때문에 문자 9 를 보는 것에 놀라지 않습니다 . 원시 바이트로 읽도록 선택할 수도 있습니다.
Cookie: JSESSIONID=27D0A0637A0449CF65B3CB20F40048AF
실제로 마지막 HTTP 헤더입니다. 그 후 우리가 업로드 한 파일의 메타와 내용을 볼 수있는 HTTP 본문이 나온다.
답변
HTTP 메시지에는 헤더 행 다음에 전송 된 데이터 본문이있을 수 있습니다. 이에 대한 응답으로 요청 된 리소스가 클라이언트 (메시지 본문의 가장 일반적인 용도)로 반환되거나 오류가있는 경우 설명 텍스트가 반환됩니다. 요청시 사용자가 입력 한 데이터 또는 업로드 된 파일이 서버로 전송됩니다.