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




servidor json (9)

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

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.


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


Puede enviar el archivo y los datos en una solicitud utilizando el tipo de contenido multipart/form-data :

En muchas aplicaciones, es posible que a un usuario se le presente un formulario. El usuario completará el formulario, incluida la información que se escribe, se genera mediante la entrada del usuario o se incluye a partir de los archivos que el usuario ha seleccionado. Cuando se completa el formulario, los datos del formulario se envían desde el usuario a la aplicación receptora.

La definición de MultiPart / Form-Data se deriva de una de esas aplicaciones ...

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

"multipart / form-data" contiene una serie de partes. Se espera que cada parte contenga un encabezado de disposición de contenido [RFC 2183] donde el tipo de disposición es "form-data", y donde la disposición contiene un parámetro (adicional) de "nombre", donde el valor de ese parámetro es el original Nombre del campo en el formulario. Por ejemplo, una parte puede contener un encabezado:

Disposición de contenido: datos de formulario; nombre = "usuario"

con el valor correspondiente a la entrada del campo "usuario".

Puede incluir información de archivo o información de campo dentro de cada sección entre límites. He implementado con éxito un servicio RESTful que requería que el usuario enviara tanto datos como un formulario, y multiparte / datos de formulario funcionaron perfectamente. El servicio se creó utilizando Java / Spring, y el cliente usaba C #, por lo que, lamentablemente, no tengo ningún ejemplo de Grails para proporcionarle información sobre cómo configurar el servicio. No necesita usar JSON en este caso, ya que cada sección de "datos de formulario" le proporciona un lugar para especificar el nombre del parámetro y su valor.

Lo bueno de usar multipart / form-data es que estás usando encabezados definidos por HTTP, por lo que te quedas con la filosofía REST de usar las herramientas HTTP existentes para crear tu servicio.


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

Hice una pregunta similar aquí:

¿Cómo subo un archivo con metadatos usando un servicio web REST?

Básicamente tienes tres opciones:

  1. Base64 codifica el archivo, a costa de aumentar el tamaño de los datos en aproximadamente un 33%.
  2. Primero envíe el archivo en un POST multipart/form-data y devuelva una ID al cliente. Luego, el cliente envía los metadatos con el ID y el servidor vuelve a asociar el archivo y los metadatos.
  3. Primero envíe los metadatos y devuelva una ID al cliente. El cliente luego envía el archivo con la ID y el servidor vuelve a asociar el archivo y los metadatos.

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.


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


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.






file-upload