service知乎 - 将文件和关联数据发布到RESTful WebService(最好是JSON)




webservice restful区别 (7)

这可能会是一个愚蠢的问题,但我有一个晚上。 在我开发RESTful API的应用程序中,我们希望客户端以JSON形式发送数据。 部分此应用程序需要客户端上传文件(通常是图片)以及有关图片的信息。

我很难在单个请求中追踪这种情况。 是否有可能将文件数据Base6464到一个JSON字符串? 我需要执行2个职位到服务器? 我应该不使用JSON吗?

作为一个方面说明,我们在后端使用Grails,并且这些服务可以由本地移动客户端(iPhone,Android等)访问,如果有任何改变的话。


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


如果你正在开发一个休息服务器,你可以这样做

  1. 让客户端通过HTTP公开文件
  2. 客户端然后可以发送带有json数据的url,例如图像文件{"file_url":"http://cockwombles.com/blah.jpg"}
  3. 服务器可以下载文件。

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

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

你基本上有三个选择:

  1. Base64对文件进行编码,代价是将数据大小增加大约33%。
  2. 首先在multipart/form-data POST中发送文件,并将ID返回给客户端。 客户端随后使用ID发送元数据,服务器将文件和元数据重新关联。
  3. 首先发送元数据,并将ID返回给客户端。 然后客户端发送带有ID的文件,服务器重新关联文件和元数据。

我知道这个线程很老,但是,我在这里错过了一个选项。 如果您想要随要上传的数据一起发送元数据(以任何格式),则可以制作一个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--

由于唯一缺少的示例是ANDROID示例 ,我将添加它。 此技术使用应在Activity类中声明的自定义AsyncTask。

private class UploadFile extends AsyncTask<Void, Integer, String> {
    @Override
    protected void onPreExecute() {
        // set a status bar or show a dialog to the user here
        super.onPreExecute();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        // progress[0] is the current status (e.g. 10%)
        // here you can update the user interface with the current status
    }

    @Override
    protected String doInBackground(Void... params) {
        return uploadFile();
    }

    private String uploadFile() {

        String responseString = null;
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost("http://example.com/upload-file");

        try {
            AndroidMultiPartEntity ampEntity = new AndroidMultiPartEntity(
                new ProgressListener() {
                    @Override
                        public void transferred(long num) {
                            // this trigger the progressUpdate event
                            publishProgress((int) ((num / (float) totalSize) * 100));
                        }
            });

            File myFile = new File("/my/image/path/example.jpg");

            ampEntity.addPart("fileFieldName", new FileBody(myFile));

            totalSize = ampEntity.getContentLength();
            httpPost.setEntity(ampEntity);

            // Making server call
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();

            int statusCode = httpResponse.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                responseString = EntityUtils.toString(httpEntity);
            } else {
                responseString = "Error, http status: "
                        + statusCode;
            }

        } catch (Exception e) {
            responseString = e.getMessage();
        }
        return responseString;
    }

    @Override
    protected void onPostExecute(String result) {
        // if you want update the user interface with upload result
        super.onPostExecute(result);
    }

}

所以,当你想上传你的文件时,只需打电话:

new UploadFile().execute();

请确保您有以下导入。 当然其他标准进口

import org.springframework.core.io.FileSystemResource


    void uploadzipFiles(String token) {

        RestBuilder rest = new RestBuilder(connectTimeout:10000, readTimeout:20000)

        def zipFile = new File("testdata.zip")
        def Id = "001G00000"
        MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>()
        form.add("id", id)
        form.add('file',new FileSystemResource(zipFile))
        def urld ='''http://URL''';
        def resp = rest.post(urld) {
            header('X-Auth-Token', clientSecret)
            contentType "multipart/form-data"
            body(form)
        }
        println "resp::"+resp
        println "resp::"+resp.text
        println "resp::"+resp.headers
        println "resp::"+resp.body
        println "resp::"+resp.status
    }

@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
}




file-upload