|
1 | | -# Resumable file upload |
| 1 | +# 파일 업로드 재개하기 |
2 | 2 |
|
3 | | -With `fetch` method it's fairly easy to upload a file. |
| 3 | +`fetch` 메서드를 사용하면 꽤 쉽게 파일을 업로드할 수 있습니다. |
4 | 4 |
|
5 | | -How to resume the upload after lost connection? There's no built-in option for that, but we have the pieces to implement it. |
| 5 | +업로드 중 연결이 끊긴 후에 업로드를 재개하려면 어떻게 해야 할까요. 그것을 위해 내장된 기능은 없지만, 부분적으로 구현할 수 있는 기능들이 있습니다. |
6 | 6 |
|
7 | | -Resumable uploads should come with upload progress indication, as we expect big files (if we may need to resume). So, as `fetch` doesn't allow to track upload progress, we'll use [XMLHttpRequest](info:xmlhttprequest). |
| 7 | +아마도 큰 용량의 파일(재 업로드를 해야 하는 상황이라면) 업로드를 재개하려면 업로드 진행률 표시가 동반되어야 합니다. `fetch` 메서드로는 업로드 진행률을 알 수 없음으로 [XMLHttpRequest](info:xmlhttprequest)를 사용합니다. |
8 | 8 |
|
9 | | -## Not-so-useful progress event |
| 9 | +## 별 도움 안 되는 진행률 이벤트 |
10 | 10 |
|
11 | | -To resume upload, we need to know how much was uploaded till the connection was lost. |
| 11 | +업로드를 재개하기 위해서, 연결이 끊기기 전까지 얼마나 업로드가 되었는지 알아야 합니다. |
12 | 12 |
|
13 | | -There's `xhr.upload.onprogress` to track upload progress. |
| 13 | +`xhr.upload.onprogress`로 업로드 진행률을 추적할 수 있습니다. |
14 | 14 |
|
15 | | -Unfortunately, it won't help us to resume the upload here, as it triggers when the data is _sent_, but was it received by the server? The browser doesn't know. |
| 15 | +불행하게도 여기 업로드 재개하기에는 도움이 되지 않고 데이터를 *보낼* 때 작동할 뿐, 서버가 데이터를 받았는지 브라우저는 알 수 없습니다. |
16 | 16 |
|
17 | | -Maybe it was buffered by a local network proxy, or maybe the remote server process just died and couldn't process them, or it was just lost in the middle and didn't reach the receiver. |
| 17 | +아마도 지역 네트워크 프락시의 지연이나, 원격 서버의 프로세스가 죽어서 처리를 하지 못하거나, 단지 중간에 손실이 일어나 리시버에 도달하지 못했을 수 있습니다. |
18 | 18 |
|
19 | | -That's why this event is only useful to show a nice progress bar. |
| 19 | +이것이 이 이벤트가 멋진 진행률을 보여주는 것 외에는 그다지 유용하지 않는 이유입니다. |
20 | 20 |
|
21 | | -To resume upload, we need to know _exactly_ the number of bytes received by the server. And only the server can tell that, so we'll make an additional request. |
| 21 | +업로드를 재개하기 위해서, 서버로부터 수신받은 바이트의 *정확한* 숫자를 알아야 합니다. 그리고 바이트의 수는 서버만이 말해줄 수 있기 때문에 추가로 요청을 해야 합니다. |
22 | 22 |
|
23 | | -## Algorithm |
| 23 | +## 알고리즘 |
24 | 24 |
|
25 | | -1. First, create a file id, to uniquely identify the file we're going to upload: |
| 25 | +1. 첫째, 업로드할 파일에 고윳값을 구분할 파일 아이디를 생성하세요. |
| 26 | + ```js |
| 27 | + let fileId = file.name + '-' + file.size + '-' + +file.lastModifiedDate; |
| 28 | + ``` |
| 29 | + 그것은 파일 업로드를 재개하기 위해 어떤 것을 재개할지 서버에 말해주기 위해 필요합니다. |
26 | 30 |
|
27 | | - ```js |
28 | | - let fileId = file.name + "-" + file.size + "-" + +file.lastModifiedDate; |
29 | | - ``` |
| 31 | + 이름이나 크기 혹은 최종 수정 날짜가 변하면 별도의 `fileId`가 생성됩니다. |
30 | 32 |
|
31 | | - That's needed for resume upload, to tell the server what we're resuming. |
| 33 | +2. 서버에 요청을 보내어 바이트가 이미 얼마나 되는지 물어봅니다. 이렇게요. |
| 34 | + ```js |
| 35 | + let response = await fetch('status', { |
| 36 | + headers: { |
| 37 | + 'X-File-Id': fileId |
| 38 | + } |
| 39 | + }); |
32 | 40 |
|
33 | | - If the name or the size or the last modification date changes, then there'll be another `fileId`. |
| 41 | + // The server has that many bytes |
| 42 | + let startByte = +await response.text(); |
| 43 | + ``` |
34 | 44 |
|
35 | | -2. Send a request to the server, asking how many bytes it already has, like this: |
| 45 | + 서버가 `X-File-Id` 헤더에서 파일 업로드를 추적한다고 가정합니다. 이는 서버사이드에 구현되어야 합니다. |
36 | 46 |
|
37 | | - ```js |
38 | | - let response = await fetch("status", { |
39 | | - headers: { |
40 | | - "X-File-Id": fileId, |
41 | | - }, |
42 | | - }); |
| 47 | + 아직 파일이 서버에 없으면 서버는 `0`으로 응답해야 합니다. |
43 | 48 |
|
44 | | - // The server has that many bytes |
45 | | - let startByte = +(await response.text()); |
46 | | - ``` |
| 49 | +3. `startByte`에서 파일을 보내기 위해 `Blob`의 `slice` 메서드를 사용합니다. |
| 50 | + ```js |
| 51 | + xhr.open("POST", "upload", true); |
47 | 52 |
|
48 | | - This assumes that the server tracks file uploads by `X-File-Id` header. Should be implemented at server-side. |
| 53 | + // File id, so that the server knows which file we upload |
| 54 | + xhr.setRequestHeader('X-File-Id', fileId); |
49 | 55 |
|
50 | | - If the file doesn't yet exist at the server, then the server response should be `0` |
| 56 | + // The byte we're resuming from, so the server knows we're resuming |
| 57 | + xhr.setRequestHeader('X-Start-Byte', startByte); |
51 | 58 |
|
52 | | -3. Then, we can use `Blob` method `slice` to send the file from `startByte`: |
| 59 | + xhr.upload.onprogress = (e) => { |
| 60 | + console.log(`Uploaded ${startByte + e.loaded} of ${startByte + e.total}`); |
| 61 | + }; |
53 | 62 |
|
54 | | - ```js |
55 | | - xhr.open("POST", "upload", true); |
| 63 | + // file can be from input.files[0] or another source |
| 64 | + xhr.send(file.slice(startByte)); |
| 65 | + ``` |
56 | 66 |
|
57 | | - // File id, so that the server knows which file we upload |
58 | | - xhr.setRequestHeader("X-File-Id", fileId); |
| 67 | + 서버에 파일 아이디인 `X-File-Id`를 보내 업로드할 파일을 알게 되고 시작 바이트인 `X-Start-Byte`를 서버에 보내 처음부터 업로드하지 않고 재개하게 합니다. |
59 | 68 |
|
60 | | - // The byte we're resuming from, so the server knows we're resuming |
61 | | - xhr.setRequestHeader("X-Start-Byte", startByte); |
| 69 | + 서버는 기록을 확인해서 파일에 업로드가 있었는지, 그리고 현재 올리는 크기가 정확히 `X-Start-Byte`인지 확인하고 데이터를 확장합니다. |
62 | 70 |
|
63 | | - xhr.upload.onprogress = (e) => { |
64 | | - console.log(`Uploaded ${startByte + e.loaded} of ${startByte + e.total}`); |
65 | | - }; |
66 | 71 |
|
67 | | - // file can be from input.files[0] or another source |
68 | | - xhr.send(file.slice(startByte)); |
69 | | - ``` |
| 72 | +여기에 Node.js로 작성된 서버와 클라이언트 시범 서버 코드가 있습니다. |
70 | 73 |
|
71 | | - Here we send the server both file id as `X-File-Id`, so it knows which file we're uploading, and the starting byte as `X-Start-Byte`, so it knows we're not uploading it initially, but resuming. |
| 74 | +Node.js는 Nginx의 서버 뒤에서 버퍼 업로드가 완료되었을 때 Node.js로 전달하기 때문에 이 사이트에서만 부분적으로 작동합니다. |
72 | 75 |
|
73 | | - The server should check its records, and if there was an upload of that file, and the current uploaded size is exactly `X-Start-Byte`, then append the data to it. |
74 | | - |
75 | | -Here's the demo with both client and server code, written on Node.js. |
76 | | - |
77 | | -It works only partially on this site, as Node.js is behind another server named Nginx, that buffers uploads, passing them to Node.js when fully complete. |
78 | | - |
79 | | -But you can download it and run locally for the full demonstration: |
| 76 | +그래도 다운로드를 받아서 로컬에서 전체 시범을 실행해보세요. |
80 | 77 |
|
81 | 78 | [codetabs src="upload-resume" height=200] |
82 | 79 |
|
83 | | -As we can see, modern networking methods are close to file managers in their capabilities -- control over headers, progress indicator, sending file parts, etc. |
| 80 | +알다시피 최신 네트워킹 메서드들은 기능 면에서 파일 매니저에 가깝습니다 -- 오버 헤더 통제, 진행률 표시, 파일을 부분적으로 보냄 등. |
84 | 81 |
|
85 | | -We can implement resumable upload and much more. |
| 82 | +이제 파일 업로드 재개를 구현할 수 있습니다. |
0 commit comments