在一个应用程序中,我正在开发RESTful API,我们希望客户端以JSON形式发送数据。这个应用程序的一部分要求客户端上传一个文件(通常是一个图像)以及关于图像的信息。

我很难在一个请求中找到这种情况。是否可以将文件数据Base64转换为JSON字符串?我是否需要向服务器发送2次帖子?我不应该使用JSON吗?

顺便说一句,我们在后端使用Grails,这些服务是由本地移动客户端(iPhone、Android等)访问的,如果有什么不同的话。


当前回答

@RequestMapping(value = "/uploadImageJson", method = RequestMethod.POST)
    public @ResponseBody Object jsongStrImage(@RequestParam(value="image") MultipartFile image, @RequestParam String jsonStr) {
-- use  com.fasterxml.jackson.databind.ObjectMapper convert Json String to Object
}

其他回答

你可以使用multipart/form-data内容类型在一个请求中发送文件和数据:

在许多应用程序中,可能会向用户显示 一种形式。用户将填写表单,包括以下信息 类型的、由用户输入生成的或包含在 用户已选择。表单填写后,从 表单从用户发送到接收应用程序。 MultiPart/Form-Data的定义就是从这些定义中派生出来的 应用程序…

从http://www.faqs.org/rfcs/rfc2388.html:

“multipart/form-data”包含一系列的部分。每个部分是 期望包含一个内容处理头[RFC 2183] 处置类型为“form-data”,其中处置包含 一个(额外的)参数“name”,其中的值 参数是表单中的原始字段名。例如,一个部分 可能包含一个头文件: 附加:格式;name = "用户" 与“user”字段的条目对应的值。

You can include file information or field information within each section between boundaries. I've successfully implemented a RESTful service that required the user to submit both data and a form, and multipart/form-data worked perfectly. The service was built using Java/Spring, and the client was using C#, so unfortunately I don't have any Grails examples to give you concerning how to set up the service. You don't need to use JSON in this case since each "form-data" section provides you a place to specify the name of the parameter and its value.

使用multipart/form-data的好处是您使用的是HTTP定义的报头,因此您坚持使用现有HTTP工具创建服务的REST理念。

您可以尝试使用https://square.github.io/okhttp/ library。 你可以设置请求主体为multipart,然后分别添加文件和json对象,如下所示:

MultipartBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("uploadFile", uploadFile.getName(), okhttp3.RequestBody.create(uploadFile, MediaType.parse("image/png")))
                .addFormDataPart("file metadata", json)
                .build();

        Request request = new Request.Builder()
                .url("https://uploadurl.com/uploadFile")
                .post(requestBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

            logger.info(response.body().string());

我知道这个线程是相当旧的,但是,我在这里错过了一个选项。如果您有元数据(任何格式),希望将其与要上传的数据一起发送,则可以发出单个多部分/相关请求。

Multipart/Related媒体类型用于由几个相互关联的主体部分组成的复合对象。

您可以查看RFC 2387规范以获得更深入的细节。

基本上,这样的请求的每个部分都可以有不同类型的内容,并且所有部分都以某种方式相关(例如,图像和它的元数据)。各部分由一个边界字符串标识,最后的边界字符串后面跟着两个连字符。

例子:

POST /upload HTTP/1.1
Host: www.hostname.com
Content-Type: multipart/related; boundary=xyz
Content-Length: [actual-content-length]

--xyz
Content-Type: application/json; charset=UTF-8

{
    "name": "Sample image",
    "desc": "...",
    ...
}

--xyz
Content-Type: image/jpeg

[image data]
[image data]
[image data]
...
--foo_bar_baz--

我在这里问了一个类似的问题:

如何使用REST web服务上传带有元数据的文件?

你基本上有三个选择:

Base64 encode the file, at the expense of increasing the data size by around 33%, and add processing overhead in both the server and the client for encoding/decoding. Send the file first in a multipart/form-data POST, and return an ID to the client. The client then sends the metadata with the ID, and the server re-associates the file and the metadata. Send the metadata first, and return an ID to the client. The client then sends the file with the ID, and the server re-associates the file and the metadata.

FormData对象:使用Ajax上传文件

XMLHttpRequest Level 2增加了对新的FormData接口的支持。 FormData对象提供了一种方法,可以轻松地构造一组表示表单字段及其值的键/值对,然后可以使用XMLHttpRequest send()方法轻松地发送这些字段。

function AjaxFileUpload() {
    var file = document.getElementById("files");
    //var file = fileInput;
    var fd = new FormData();
    fd.append("imageFileData", file);
    var xhr = new XMLHttpRequest();
    xhr.open("POST", '/ws/fileUpload.do');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
             alert('success');
        }
        else if (uploadResult == 'success')
             alert('error');
    };
    xhr.send(fd);
}

https://developer.mozilla.org/en-US/docs/Web/API/FormData