英文:
Unable to send data in chunks to server in Golang
问题
我完全不了解Golang。我正在尝试从客户端向服务器发送一个文件。客户端应该将文件分成较小的块并将其发送到服务器暴露的REST端点。服务器应该合并这些块并保存文件。
这是我目前编写的客户端和服务器代码。当我运行这段代码复制一个大小为39字节的文件时,客户端向服务器发送了两个请求。但是服务器显示了以下错误信息。
2017/05/30 20:19:28 无法访问上传的文件:意外的EOF
2017/05/30 20:19:28 无法访问上传的文件:multipart: NextPart: EOF
英文:
I'm completely new to Golang. I am trying to send a file from the client to the server. The client should split it into smaller chunks and send it to the rest end point exposed by the server. The server should combine those chunks and save it.
This is the client and server code I have written so far. When I run this to copy a file of size 39 bytes, the client is sending two requests to the server. But the server is displaying the following errors.
2017/05/30 20:19:28 Was not able to access the uploaded file: unexpected EOF
2017/05/30 20:19:28 Was not able to access the uploaded file: multipart: NextPart: EOF
答案1
得分: 1
你正在将缓冲区与文件分成单独的块,并将它们作为单独的HTTP消息发送。这不是multipart
的正确使用方式。
multipart
MIME意味着单个HTTP消息可以包含一个或多个实体,引用HTTP RFC的说法:
> MIME提供了一些“multipart”类型——在单个消息体中封装一个或多个实体。所有multipart类型共享一个通用的语法,如RFC 2046的第5.1.1节所定义。
你应该发送整个文件,并将其作为单个HTTP消息发送(文件内容应该是一个单独的实体)。HTTP协议会处理剩下的部分,但如果你计划传输的文件很大(如> 2GB
),你可以考虑使用FTP。
英文:
You are dividing buffer with the file into separate chunks and sending each of them as separate HTTP message. This is not how multipart
is intended to be used.
multipart
MIME means that a single HTTP message may contain one or more entities, quoting HTTP RFC:
> MIME provides for a number of "multipart" types -- encapsulations of
> one or more entities within a single message-body. All multipart types
> share a common syntax, as defined in section 5.1.1 of RFC 2046
You should send the whole file and send it in a single HTTP message (file contents should be a single entity). The HTTP protocol will take care of the rest but you may consider using FTP if the files you are planning to transfer are large (like > 2GB
).
答案2
得分: 0
如果你正在使用multipart/form-data,那么预期是将整个文件作为单个字节流发送。Go可以轻松处理多GB大小的文件。但是你的代码需要对此进行智能处理。
ioutil.ReadAll(r.Body)
是不可行的,除非你确定文件非常小。请不要这样做。multipartReader, err := r.MultipartReader()
使用一个multipart reader。这将按照编码中包含的顺序迭代上传的文件。这很重要,因为你可以完全避免将文件保存在内存中,并使用Copy
从一个文件句柄复制到另一个文件句柄。这是处理大文件的简便方法。- 你可能会遇到中间代理和反向代理的问题。我们需要更改Nginx的默认设置,以便它不会截断大文件。Nginx(或者你可能使用的其他反向代理)需要进行配合,因为它们通常会默认设置非常小的文件大小上限,例如300MB。
- 即使你认为你已经通过某种文件分块技巧解决了上传问题,你仍然需要处理下载时的大文件。Go可以通过从文件句柄到文件句柄的
Copy
操作高效地处理单个大文件。如果你想要高性能地下载你上传的文件,你还需要支持部分内容(http 206)和未修改(304)。某些浏览器在涉及大型视频等内容时会忽略你的请求,要求获取部分内容。因此,如果你不支持这一点,某些内容将无法下载。
如果你想使用一些技巧来分割文件并分段发送,那么你将需要使用特定的JavaScript库。如果你希望从任何客户端以编程方式访问你的Go服务器,这将对互操作性造成相当大的伤害。但是也许你无法修复强加大小限制的中间代理,而且你确实想要将文件分割成块。你将需要大量工作来处理以分块方式上传的文件的下载。
英文:
If you are using a multipart/form-data, then it is expected to take the entire file and send it up as a single byte stream. Go can handle multi-gigabyte files easily this way. But your code needs to be smart about this.
ioutil.ReadAll(r.Body)
is out of the question unless you know for sure that the file will be very small. Please don't do this.multipartReader, err := r.MultipartReader()
use a multipart reader. This will iterate over uploading files, in the order they are included in the encoding. This is important, because you can keep the file entirely out of memory, and do aCopy
from one filehandle to another. This is how large files are handled easily.- You will have issues with middle-boxes and reverse proxies. We have to change defaults in Nginx so that it will not cut off large files. Nginx (or whatever reverse-proxy you might use) will need to cooperate, as they often are going to default to some really tiny file size max like 300MB.
- Even if you think you dealt with this issue on upload with some file part trick, you will then need to deal with large files on download. Go can do single large files very efficiently by doing a
Copy
from filehandle to filehandle. You will also end up needing to support partial content (http 206) and not modified (304) if you want great performance for downloading files that you uploaded. Some browsers will ignore your pleas to not ask for partial content when things like large video is involved. So, if you don't support this, then some content will fail to download.
If you want to use some tricks to cut up files and send them in parts, then you will end up needing to use a particular Javascript library. This is going to be quite harmful to interoperability if you are going for programmatic access from any client to your Go server. But maybe you can't fix middle-boxes that impose size limits, and you really want to cut files up into chunks. You will have a lot of work to handle downloading the files that you managed to upload in chunks.
答案3
得分: -2
你正在尝试的是使用大多数其他语言编写的具有TCP连接的典型代码,在GO中,你可以使用net.Listen并最终在listener对象上接受连接。然后这应该没问题。
英文:
What you are trying to do is the typical code that is written with a tcp connection with most other languages, in GO you can use tcp too with net.Listen and eventually accept on the listener object. Then this should be fine.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论