Posting a File and Associated Data to a RESTful WebService preferably as JSON

后端 未结 11 840
没有蜡笔的小新
没有蜡笔的小新 2020-11-22 10:45

This is probably going to be a stupid question but I\'m having one of those nights. In an application I am developing RESTful API and we want the client to send data as JSON

相关标签:
11条回答
  • 2020-11-22 11:14

    Please ensure that you have following import. Ofcourse other standard imports

    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
        }
    
    0 讨论(0)
  • 2020-11-22 11:15

    You can send the file and data over in one request using the multipart/form-data content type:

    In many applications, it is possible for a user to be presented with a form. The user will fill out the form, including information that is typed, generated by user input, or included from files that the user has selected. When the form is filled out, the data from the form is sent from the user to the receiving application.

    The definition of MultiPart/Form-Data is derived from one of those applications...

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

    "multipart/form-data" contains a series of parts. Each part is expected to contain a content-disposition header [RFC 2183] where the disposition type is "form-data", and where the disposition contains an (additional) parameter of "name", where the value of that parameter is the original field name in the form. For example, a part might contain a header:

    Content-Disposition: form-data; name="user"

    with the value corresponding to the entry of the "user" field.

    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.

    The good thing about using multipart/form-data is that you're using HTTP-defined headers, so you're sticking with the REST philosophy of using existing HTTP tools to create your service.

    0 讨论(0)
  • 2020-11-22 11:19

    I wanted send some strings to backend server. I didnt use json with multipart, I have used request params.

    @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 would look like

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

    I am passing two params (uuid and type) along with file upload. Hope this will help who don't have the complex json data to send.

    0 讨论(0)
  • 2020-11-22 11:22

    I asked a similar question here:

    How do I upload a file with metadata using a REST web service?

    You basically have three choices:

    1. 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.
    2. 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.
    3. 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.
    0 讨论(0)
  • 2020-11-22 11:27

    Here is my approach API (i use example) - as you can see, you I don't use any file_id (uploaded file identifier to the server) in API:

    1. Create photo object on server:

       POST: /projects/{project_id}/photos   
       body: { name: "some_schema.jpg", comment: "blah"}
       response: photo_id
      
    2. Upload file (note that file is in singular form because it is only one per photo):

       POST: /projects/{project_id}/photos/{photo_id}/file
       body: file to upload
       response: -
      

    And then for instance:

    1. Read photos list

       GET: /projects/{project_id}/photos
       response: [ photo, photo, photo, ... ] (array of objects)
      
    2. Read some photo details

       GET: /projects/{project_id}/photos/{photo_id}
       response: { id: 666, name: 'some_schema.jpg', comment:'blah'} (photo object)
      
    3. Read photo file

       GET: /projects/{project_id}/photos/{photo_id}/file
       response: file content
      

    So the conclusion is that, first you create an object (photo) by POST, and then you send second request with the file (again POST). To not have problems with CACHE in this approach we assume that we can only delete old photos and add new - no update binary photo files (because new binary file is in fact... NEW photo). However if you need to be able to update binary files and cache them, then in point 4 return also fileId and change 5 to GET: /projects/{project_id}/photos/{photo_id}/files/{fileId}.

    0 讨论(0)
  • 2020-11-22 11:29

    I know this question is old, but in the last days I had searched whole web to solution this same question. I have grails REST webservices and iPhone Client that send pictures, title and description.

    I don't know if my approach is the best, but is so easy and simple.

    I take a picture using the UIImagePickerController and send to server the NSData using the header tags of request to send the picture's data.

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

    At the server side, I receive the photo using the code:

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

    I don't know if I have problems in future, but now is working fine in production environment.

    0 讨论(0)
提交回复
热议问题