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

Google App Engine Java HTTP Post Image from API Method to Servlet

希望有人能帮帮我。

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

问题是 - 根本没有张贴图片。

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

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

Solved, see answer below!


Android:

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 Class:

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

根据 Google App Engine Docs 不允许您获取自己的 URL:

To prevent an app from causing an endless recursion of requests, a request handler is not allowed to fetch its own URL. It is still possible to cause an endless recursion with other means, so exercise caution if your app can be made to fetch requests for URLs supplied by the user.

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

Android:

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