如何使用REST Web服务上传包含元数据的文件?

我有一个REST Web服务,当前公开此URL:

HTTP://服务器/数据/媒体

用户可以在POST以下JSON:

{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873
}

以创建新的媒体元数据。

现在我需要能够与媒体元数据同时上传文件。 这是怎么回事? 我可以引入一个名为file和base64的新属性,但我想知道是否有更好的方法。

还有一些HTML表单可以发送multipart/form-data ,但我使用的是REST Web服务,如果可能的话,我想坚持使用JSON。


我同意格雷格的观点,两阶段的方法是一个合理的解决方案,但我会以相反的方式去做。 我会做:

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和文件(或多个文件)不是RESTful:

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']将是一个包含所有文件的字符串,您必须自己解析 - 不知道该怎么做,但我相信这并不困难,或者更好只是使用以前的方法。

@<的不同之处在于@使文件作为文件上载被附加,而<作为文本字段附加文件的内容。

PS仅仅因为我将curl用作生成POST请求的方式并不意味着不能从Python等编程语言发送完全相同的HTTP请求,也不能使用任何功能强大的工具。


解决这个问题的一种方法是将上传分为两个阶段。 首先,您可以使用POST上传文件本身,其中服务器将一些标识符返回给客户端(标识符可能是文件内容的SHA1)。 然后,第二个请求将元数据与文件数据相关联:

{
    "Name": "Test",
    "Latitude": 12.59817,
    "Longitude": 52.12873,
    "ContentID": "7a788f56fa49ae0ba5ebde780efe4d6a89b5db47"
}

包括编码到JSON请求本身的文件数据base64将增加传输数据的大小33%。 根据文件的整体大小,这可能很重要,也可能不重要。

另一种方法可能是使用原始文件数据的POST,但在HTTP请求头中包含任何元数据。 但是,这在基本的REST操作之外有点让人头疼,并且对于某些HTTP客户端库可能会更加尴尬。

链接地址: http://www.djcxy.com/p/8561.html

上一篇: How do I upload a file with metadata using a REST web service?

下一篇: Powershell & Curl