Google App Engine Java HTTP Post 图像从 API 方法到 Servlet

Posted

技术标签:

【中文标题】Google App Engine Java HTTP Post 图像从 API 方法到 Servlet【英文标题】:Google App Engine Java HTTP Post Image from API Method to Servlet 【发布时间】:2015-04-23 01:14:09 【问题描述】:

希望有人能帮帮我。

我想将 url 作为字符串发送到客户端端点函数,然后我希望端点函数下载图像并通过 HTTP Post 请求将其发送到我的 servlet(也在 GAE 上运行)。

问题是 - 根本没有发布图片。

这很奇怪,因为如果我在 android 客户端上使用完全相同的代码(HttpPost 类),它可以正常工作 - 图像被发布到 servlet 并且 servlet 将图像存储到数据存储区/blobstore 中。

是否可以从客户端端点函数向 servlet 发送 HTTP Post 请求?

已解决,见下方答案!


安卓:

BackendApi.anyMethod("url-to-any-image").execute();

客户端端点功能:

@ApiMethod(path = "anyMethod")
public void anyMethod(@Named("url") String url) 
  // --------------------------------------------------
  // No input validation here - just a proof of concept
  // --------------------------------------------------

  try 
    // Download image
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    Resources.asByteSource(new URL(url)).copyTo(buffer);

    // Upload image
    HttpPost httpPost = new HttpPost();
    httpPost.setTarget(new URL(BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/upload")));
    httpPost.add("image", buffer.toByteArray());
    httpPost.send();
   catch (IOException e) 
    LOG.log(Level.WARNING, e.getMessage(), e);
  


HttpPost 类:

public class HttpPost 

  private final static String CRLF = "\r\n";

  private String boundary;

  private URL url;
  private ByteArrayOutputStream buffer;

  public HttpPost() 
    // Generate random boundary
    // Boundary length: max. 70 characters (not counting the two leading hyphens)
    byte[] random = new byte[40];
    new Random().nextBytes(random);
    boundary = Base64.encodeBase64String(random);

    // Init buffer
    buffer = new ByteArrayOutputStream();
  

  public void setTarget(URL url) 
    this.url = url;
  

  public void add(String key, String value) throws IOException 
    addToBuffer("--" + boundary + CRLF);
    addToBuffer("Content-Disposition: form-data; name=\"" + key + "\"" + CRLF);
    addToBuffer("Content-Type: text/plain; charset=UTF-8" + CRLF + CRLF);
    addToBuffer(value + CRLF);
  

  public void add(String key, byte[] fileBytes) throws IOException 
    addToBuffer("--" + boundary + CRLF);
    addToBuffer("Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + key + "\"" + CRLF);
    addToBuffer("Content-Type: application/octet-stream" + CRLF);
    addToBuffer("Content-Transfer-Encoding: binary" + CRLF + CRLF);
    addToBuffer(fileBytes);
    addToBuffer(CRLF);
  

  public void send() throws IOException 
    // Add boundary end
    addToBuffer("--" + boundary + "--" + CRLF);

    // Open url connection
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setDoOutput(true);
    connection.setRequestMethod("POST");
    connection.setRequestProperty("Connection", "Keep-Alive");
    connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
    connection.setRequestProperty("User-Agent", "Google App Engine");

    // Open data output stream
    DataOutputStream request = new DataOutputStream(connection.getOutputStream());
    request.write(buffer.toByteArray());
    request.flush();
    request.close();

    // Close connection
    connection.disconnect();
  

  private void addToBuffer(String string) throws IOException 
    buffer.write(string.getBytes());
  

  private void addToBuffer(byte[] bytes) throws IOException 
    buffer.write(bytes);
  


Http Servlet:

public class Upload extends HttpServlet 
  private static final Logger LOG = Logger.getLogger(Upload.class.getName());
  private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();

  public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException 
    Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(request);

    List<BlobKey> blobKeys = blobs.get("image");

    if (blobKeys == null) 
      LOG.warning("No blobkeys found");
      return;
    

    // Get blob key
    BlobKey blobKey = blobKeys.get(0);

    if (blobKey == null) 
      LOG.warning("No blobkey found");
      return;
    

    // Create new image object
    Image image = new Image();
    image.setBlobKey(blobKey);
    image.setTimestamp(new Date());

    // Save image to datastore
    OfyService.ofy().save().entity(image).now();

    LOG.log(Level.INFO, "Image upload successful");
  

【问题讨论】:

【参考方案1】:

根据Google App Engine Docs,您不能获取自己的 URL:

为防止应用程序导致请求无休止地递归,请求处理程序不得获取其自己的 URL。使用其他方式仍然可能导致无限递归,因此如果您的应用可以获取用户提供的 URL 请求,请谨慎行事。

这意味着这样做的唯一方法是在 Android 客户端上下载图像,然后将其发布到 HttpServlet。

安卓:

try 
    // Download image to the Android client
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    Resources.asByteSource(new URL(url)).copyTo(buffer);

    // Upload image to HttpServlet
    HttpPost httpPost = new HttpPost();
    httpPost.setTarget(new URL("http-servlet-upload-url"));
    httpPost.add("image", buffer.toByteArray());
    httpPost.send();
   catch (IOException e) 
    Logcat.error(e.getMessage());
  

【讨论】:

以上是关于Google App Engine Java HTTP Post 图像从 API 方法到 Servlet的主要内容,如果未能解决你的问题,请参考以下文章

在 Google App Engine 上解压缩 Java 中的大 blob

Google App Engine (Java) + Spring 管理的 PersistenceManager

在 Google App Engine/Java 中实现通配符搜索

Google-App-Engine 上的 Grails - 它死了吗? [关闭]

google app engine java - 基于域的重定向

在单个 Google App Engine 项目中同时使用 Java 和 Python