2013-04-14 5 views
4

Я пытаюсь вызвать этот конкретный метод http://developers.box.com/docs/#files-upload-a-file в API-интерфейсе Box с помощью клиентской библиотеки Google HTTP v1.14.1. В настоящее время я не вижу никакого способа сделать это.Многопользовательский запрос на API-интерфейс API через HTTP-клиент Google

Если бы я использовал http://hc.apache.org/httpclient-3.x/methods/multipartpost.html, я бы добавил 2 элемента StringPart и 1 элемент FilePart.

В клиентской библиотеке Google HTTP я вижу только классы MultipartContent и Part, которые, похоже, не могут обрабатывать чистые пары имя/значение, как указано в StringPart.

Вот отрывок из примеров клиента Apache HTTP:

HttpPost httppost = new HttpPost("http://localhost:8080" + 
       "/servlets-examples/servlet/RequestInfoExample"); 

FileBody bin = new FileBody(new File(args[0])); 
StringBody comment = new StringBody("A binary file of some kind"); 

MultipartEntity reqEntity = new MultipartEntity(); 
reqEntity.addPart("bin", bin); 
reqEntity.addPart("comment", comment); 

httppost.setEntity(reqEntity); 

Я хочу сделать нечто подобное, но с использованием клиента Google HTTP. Любые предложения приветствуются!

ответ

6

После некоторого расследования я обнаружил, что мне нужен Content-Type: multipart/form-data для API-интерфейса Box и надлежащим образом создайте запрос. Это было невозможно с версией HTTP-клиента Google, которую я использовал, поэтому я внедрил класс MultipartFormDataContent и отлично вписывается в библиотеку. Вот полный список класса. Возможно, он может быть включен в библиотеку.

/* 
* Copyright (c) 2013 Google Inc. 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 
* in compliance with the License. You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software distributed under the License 
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 
* or implied. See the License for the specific language governing permissions and limitations under 
* the License. 
*/ 
/** 
* This is a modification of com.google.api.client.http.MultipartContent from 
* Google HTTP Client library to support multipart/form-data requests. 
* 
* The original author is Yaniv Inbar. 
*/ 
public class MultipartFormDataContent extends AbstractHttpContent { 
    private static final String NEWLINE = "\r\n"; 
    private static final String TWO_DASHES = "--"; 
    private ArrayList<Part> parts = new ArrayList<Part>(); 

    public MultipartFormDataContent() { 
     super(new HttpMediaType("multipart/form-data").setParameter("boundary", "__END_OF_PART__")); 
    } 

    @Override 
    public void writeTo(OutputStream out) throws IOException { 
     Writer writer = new OutputStreamWriter(out, getCharset()); 
     String boundary = getBoundary(); 
     for (Part part : parts) { 
      HttpHeaders headers = new HttpHeaders().setAcceptEncoding(null); 
      if (part.headers != null) { 
       headers.fromHttpHeaders(part.headers); 
      } 
      headers.setContentEncoding(null) 
        .setUserAgent(null) 
        .setContentType(null) 
        .setContentLength(null); 
      // analyze the content 
      HttpContent content = part.content; 
      StreamingContent streamingContent = null; 
      String contentDisposition = String.format("form-data; name=\"%s\"", part.name); 
      if (part.filename != null) { 
       headers.setContentType(content.getType()); 
       contentDisposition += String.format("; filename=\"%s\"", part.filename); 
      } 
      headers.set("Content-Disposition", contentDisposition); 
      HttpEncoding encoding = part.encoding; 
      if (encoding == null) { 
       streamingContent = content; 
      } else { 
       headers.setContentEncoding(encoding.getName()); 
       streamingContent = new HttpEncodingStreamingContent(content, encoding); 
      } 
      // write separator 
      writer.write(TWO_DASHES); 
      writer.write(boundary); 
      writer.write(NEWLINE); 
      // write headers 
      HttpHeaders.serializeHeadersForMultipartRequests(headers, null, null, writer); 
      // write content 
      if (streamingContent != null) { 
       writer.write(NEWLINE); 
       writer.flush(); 
       streamingContent.writeTo(out); 
       writer.write(NEWLINE); 
      } 
     } 
     // write end separator 
     writer.write(TWO_DASHES); 
     writer.write(boundary); 
     writer.write(TWO_DASHES); 
     writer.write(NEWLINE); 
     writer.flush(); 
    } 

    @Override 
    public boolean retrySupported() { 
     for (Part part : parts) { 
      if (!part.content.retrySupported()) { 
       return false; 
      } 
     } 
     return true; 
    } 

    @Override 
    public MultipartFormDataContent setMediaType(HttpMediaType mediaType) { 
     super.setMediaType(mediaType); 
     return this; 
    } 

    /** 
    * Adds an HTTP multipart part. 
    * 
    * <p> 
    * Overriding is only supported for the purpose of calling the super 
    * implementation and changing the return type, but nothing else. 
    * </p> 
    */ 
    public MultipartFormDataContent addPart(Part part) { 
     parts.add(Preconditions.checkNotNull(part)); 
     return this; 
    } 

    /** 
    * Sets the boundary string to use. 
    * 
    * <p> 
    * Defaults to {@code "END_OF_PART"}. 
    * </p> 
    * 
    * <p> 
    * Overriding is only supported for the purpose of calling the super 
    * implementation and changing the return type, but nothing else. 
    * </p> 
    */ 
    public MultipartFormDataContent setBoundary(String boundary) { 
     getMediaType().setParameter("boundary", Preconditions.checkNotNull(boundary)); 
     return this; 
    } 

    /** 
    * Single part of a multi-part request. 
    * 
    * <p> 
    * Implementation is not thread-safe. 
    * </p> 
    */ 
    public static final class Part { 
     private String name; 
     private String filename; 
     private HttpContent content; 
     private HttpHeaders headers; 
     private HttpEncoding encoding; 

     public Part setContent(HttpContent content) { 
      this.content = content; 
      return this; 
     } 

     public Part setHeaders(HttpHeaders headers) { 
      this.headers = headers; 
      return this; 
     } 

     public Part setEncoding(HttpEncoding encoding) { 
      this.encoding = encoding; 
      return this; 
     } 

     public Part setName(String name) { 
      this.name = name; 
      return this; 
     } 

     public Part setFilename(String filename) { 
      this.filename = filename; 
      return this; 
     } 
    } 
} 
+1

Типичный, что я нашел это после того, как я реализовал свое ... вздох. ну, по крайней мере, мне есть, что проверить! –

+0

@ Chris.Jenkins Это была хорошая практика для внутренних правил HTTP для меня. Надеюсь, это было то же самое для вас. По крайней мере, теперь я знаю, что существует 9 (NINE) подтипов типа многостраничного контента, и все они несовместимы друг с другом. – nucleo

+0

На самом деле, даже 10 подтипов http://en.wikipedia.org/wiki/MIME#Multipart_subtypes – nucleo

2

я боролся с этим небольшим ограничением в Google-HTTP-Java-клиенте в течение нескольких месяцев, и я пришел давно с уродливой и избыточной версией старого класса MultipartRelatedContent. Теперь я обновил библиотеку Google до последней версии 1.15.0-rc, и я обнаружил, что было довольно легко подклассифицировать MultipartContent и сделать что-то достойное, которое должно работать с любыми «multipart/form-data» содержание.

На данный момент вы можете найти его здесь: https://github.com/Luluvise/droid-utils/blob/master/src/com/google/api/client/http/MultipartFormDataContent.java (но я скоро сделаю запрос тянуть для этого должны быть интегрирован в библиотеке Google).

короткий пример использования:

File file = new File("/path/image.jpg"); 
FileContent fileContent = new FileContent("application/octet-stream", file); 
MultipartFormDataContent multipart = new MultipartFormDataContent(); 
multipart.addPart(new Part(fileContent), "image", file.getName()); 
request.setContent(multipart); // sets the content to the request 

"изображение" будет значение "имя" ключа в "Content-Disposition" заголовка , и имя файла (image.jpg в этом случае) будет (необязательным) значением для ключа «filename».

Точно так же вы можете добавить столько разных частей, сколько хотите (также вложенное другое «многочастное/смешанное» содержимое, просто убедитесь, что вы используете другую граничную строку) для многостраничного содержимого первого уровня.

+0

Честно говоря, я уже реализовал свой класс, когда увидел этот вопрос. Моя реализация использует MultipartContent как суперкласс в первую очередь и не копирует (окончательный) класс Part, который, очевидно, не предназначен для подкласса в библиотеке. Однако не хотел украсть какой-либо кредит. Юджин также попросил пример, и я предоставил его. Я не против, чтобы вы отмечали мой ответ как дубликат, если вы так думаете. – fast3r

+0

@ fast3r Прежде всего, спасибо за вашу работу! Я пытаюсь использовать свой класс для своих целей, но перед ним стоит проблема, а я пытаюсь отправить JsonHttpContent. Я всегда получаю пустой объект на своем сервере. Любые предложения, пожалуйста? –

+0

Привет, Я использовал класс с содержанием Json, и у меня не возникло никаких проблем. Вы смешиваете части различного типа и кодировки? Можете ли вы опубликовать созданный контент запроса? Я сделаю еще несколько тестов, чтобы проверить, есть ли какие-либо проблемы. – fast3r

Смежные вопросы