test - 將文件和關聯數據發佈到RESTful WebService(最好是JSON)




restful file download example (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的文件,服務器重新關聯文件和元數據。

我知道這個問題很老,但在最後幾天我搜索了整個網絡來解決這個問題。 我有Grails REST webservices和iPhone Client發送圖片,標題和說明。

我不知道我的方法是否最好,但是非常簡單。

我使用UIImagePickerController拍攝一張照片,並使用發送圖片數據的請求的標頭標籤向服務器發送NSData。

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"myServerAddress"]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:UIImageJPEGRepresentation(picture, 0.5)];
[request setValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"myPhotoTitle" forHTTPHeaderField:@"Photo-Title"];
[request setValue:@"myPhotoDescription" forHTTPHeaderField:@"Photo-Description"];

NSURLResponse *response;

NSError *error;

[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

在服務器端,我使用代碼接收照片:

InputStream is = request.inputStream

def receivedPhotoFile = (IOUtils.toByteArray(is))

def photo = new Photo()
photo.photoFile = receivedPhotoFile //photoFile is a transient attribute
photo.title = request.getHeader("Photo-Title")
photo.description = request.getHeader("Photo-Description")
photo.imageURL = "temp"    

if (photo.save()) {    

    File saveLocation = grailsAttributes.getApplicationContext().getResource(File.separator + "images").getFile()
    saveLocation.mkdirs()

    File tempFile = File.createTempFile("photo", ".jpg", saveLocation)

    photo.imageURL = saveLocation.getName() + "/" + tempFile.getName()

    tempFile.append(photo.photoFile);

} else {

    println("Error")

}

我不知道我將來是否有問題,但現在在生產環境中工作正常。


由於唯一缺少的示例是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