una - Publicación de un archivo y datos asociados a un servicio web RESTful preferiblemente como JSON




servidor json (8)

Aquí está mi API de enfoque (yo uso ejemplo) - como puede ver, usted no usa ningún ID de archivo (identificador de archivo cargado en el servidor) en la API:

1.Crear el objeto 'foto' en el servidor:

POST: /projects/{project_id}/photos   
params in: {name:some_schema.jpg, comment:blah}
return: photo_id

2. Cargue el archivo (tenga en cuenta que 'archivo' está en forma singular porque es solo uno por foto):

POST: /projects/{project_id}/photos/{photo_id}/file
params in: file to upload
return: -

Y luego, por ejemplo:

3.Leer lista de fotos

GET: /projects/{project_id}/photos
params in: -
return: array of objects: [ photo, photo, photo, ... ]

4.Lea algunos detalles de la foto

GET: /projects/{project_id}/photos/{photo_id}
params in: -
return: photo = { id: 666, name:'some_schema.jpg', comment:'blah'}

5. leer el archivo de fotos

GET: /projects/{project_id}/photos/{photo_id}/file
params in: -
return: file content

Entonces, la conclusión es que primero creas un objeto (foto) por POST y luego envías una solicitud secod con el archivo (otra vez POST).

Probablemente esta sea una pregunta estúpida, pero tengo una de esas noches. En una aplicación estoy desarrollando una API REST y queremos que el cliente envíe datos como JSON. Parte de esta aplicación requiere que el cliente cargue un archivo (generalmente una imagen) así como información sobre la imagen.

Estoy teniendo dificultades para rastrear cómo sucede esto en una sola solicitud. ¿Es posible basar los datos del archivo en una cadena JSON? ¿Tendré que realizar 2 publicaciones al servidor? ¿No debería usar JSON para esto?

Como nota al margen, estamos usando Grails en el backend y estos servicios son accedidos por clientes móviles nativos (iPhone, Android, etc.), si alguno de ellos hace una diferencia.


Como el único ejemplo que falta es el ejemplo de ANDROID , lo agregaré. Esta técnica utiliza una AsyncTask personalizada que debe declararse dentro de su clase de actividad.

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);
    }

}

Entonces, cuando quieras subir tu archivo solo llama:

new UploadFile().execute();

Objetos de FormData: carga archivos usando Ajax

XMLHttpRequest Level 2 agrega soporte para la nueva interfaz FormData. Los objetos FormData proporcionan una manera de construir fácilmente un conjunto de pares clave / valor que representan campos de formulario y sus valores, que luego pueden enviarse fácilmente usando el método de envío () XMLHttpRequest.

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


Por favor, asegúrese de que tiene la siguiente importación. Por supuesto, otras importaciones estándar

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
    }

Quería enviar algunas cadenas al servidor backend. No usé json con multiparte, he usado los parámetros de solicitud.

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void uploadFile(HttpServletRequest request,
        HttpServletResponse response, @RequestParam("uuid") String uuid,
        @RequestParam("type") DocType type,
        @RequestParam("file") MultipartFile uploadfile)

Url se vería como

http://localhost:8080/file/upload?uuid=46f073d0&type=PASSPORT

Estoy pasando dos parámetros (uuid y tipo) junto con la carga de archivos. Espero que esto ayude a quienes no tienen los datos complejos de json para enviar.


Sé que esta pregunta es antigua, pero en los últimos días había buscado en toda la web para resolver esta misma pregunta. Tengo servicios web REST de Grails y iPhone Client que envían imágenes, títulos y descripciones.

No sé si mi enfoque es el mejor, pero es tan fácil y simple.

Tomo una imagen utilizando el UIImagePickerController y envío al servidor los datos NS utilizando las etiquetas de encabezado de solicitud para enviar los datos de la imagen.

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];

En el lado del servidor, recibo la foto usando el código:

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")

}

No sé si tengo problemas en el futuro, pero ahora funciona bien en el entorno de producción.


Si está desarrollando un servidor de descanso, puede hacer esto.

  1. Haga que el cliente exponga el archivo a través de HTTP.
  2. El cliente puede enviar la url con sus datos json, por ejemplo, un archivo de imagen {"file_url":"http://cockwombles.com/blah.jpg"}
  3. El servidor puede descargar el archivo.

@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