如何在将 Blob 上传到 Blobstore 的 POST 请求中提交文本字段并在 Blob 的上传处理程序中检索它?

Posted

技术标签:

【中文标题】如何在将 Blob 上传到 Blobstore 的 POST 请求中提交文本字段并在 Blob 的上传处理程序中检索它?【英文标题】:How can I submit a text field in the POST request that uploads a blob to the Blobstore and retrieve it in the upload handler for the blob? 【发布时间】:2014-12-07 06:27:55 【问题描述】:

我在 *** 上阅读了几个类似的问题,但尚未找到解决此问题的方法。

我正在通过 HTTPPost 将 Blob 从 android 上传到 App Engine 的 Blobstore 到 Blobstore 服务生成的上传 URL。我希望能够使用标识此 blob 的此请求发送一些文本元数据。我想在上传 blob 后调用的上传处理程序 servlet 中检索此信息以及 blob 键。

问题是 blob 是使用多部分编码上传的,并且 App Engine 不支持 Servlet v3.0 标准,所以我不能使用 req.getPart() 来获取文本部分。 (blob 本身是由 Blobstore 服务返回的,所以请求的一部分已经为我们解析好了。)

如何通过仅传递一个文本参数以及上传到 Blobstore 的文件并在上传 Blob 后调用的 servlet 中检索它来解决此问题?

非常感谢您的帮助!非常坚持这个!

这是我在 Android 上用于 HttpPost 的代码:

        File file = new File(filePath);
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder
                .create();
        entityBuilder.addBinaryBody("file", file);           
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(blobUploadURL);
        httpPost.setEntity(entityBuilder.build());
        try 
            HttpResponse response = httpClient.execute(httpPost);
            statusCode = response.getStatusLine().getStatusCode();
        

更新(2014 年 12 月 8 日):

在为 HttpPost 请求构建多部分实体之前,我向实体构建器添加了一个文本主体,如下所示:

        String param="value";
        entityBuilder.addTextBody("param", param);

对于在 blob 上传后处理 Blobstore 回调的 servlet,我使用 Google 在 this 教程中描述的方法来解析 App Engine 上的 HttpPost 请求,如下所示:

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException   

    String paramNames="default";

    try 
        ServletFileUpload upload=new ServletFileUpload();
        FileItemIterator iterator=upload.getItemIterator(req);
        while(iterator.hasNext())
            FileItemStream item=iterator.next();
            InputStream stream=item.openStream();
            if(item.isFormField())
                paramNames+=item.getFieldName() + ", ";
            
        
     catch (FileUploadException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
        paramNames="error";
    

    //save the paramNames variable in the Datastore for debugging later
    saveParamNamesInDatastore(paramNames);

但是,当我在此操作后检查数据存储中的 paramNames 变量时,它的值仍然是“默认值”。这意味着在 Blobstore 传递给上传处理程序 servlet 的重写 POST 请求中没有找到表单字段。从这里到哪里去??

【问题讨论】:

【参考方案1】:

有一种方法可以将元数据与您的 blob 一起发布,其中包含 blobkey 无法表示的信息:

    在您的上传表单中包含以下内容:

    method="post" enctype="multipart/form-data"
    

    现在您可以添加隐藏字段:

    <input type="hidden" name="myName" value="<%= myName %>"/>
    

    或者您可以添加输入字段:

    <input type="text" name="myText" size="50" value="Enter your text"/>
    

    在您的 servlet 中,确保 post 处理程序读取元数据

    String userName = req.getParameter("myName");
    

    现在您有了包含所有信息的上传表单。

    当您传递信息以服务于 blob 时,您可以使用

    &blobkey=daffedafdfe&myName=Blah
    

因此,您并没有将信息完全存储在 blob 本身中,但您可以将其包含在上传表单中。

【讨论】:

感谢您的建议!我相信 request.setParameter() 不适用于多部分格式编码。你能确认它是否适合你吗?如果是,查看上传请求的 Java 代码和 Blob 上传处理程序将非常有帮助。 为什么在请求对象上需要 .setParameter?多表单应该向您的处理程序发送一个包含所有字段(包括您的表单提供的元数据)的帖子。因此,在您的 servlet 的 Post 处理程序中,只需使用 .getParameter("parameterName") 并使用 Blob 提取您想要的元数据。 谢谢!我将在上传处理程序 servlet 中测试 request.getParameter("paramName") 方法,但我怀疑它会起作用。你以前试过这个吗? 是的,我在我的生产代码中有它 :) 确保字段由您的表单传递,如果不是用户输入,则确保存在隐藏字段。只要它通过 Post 传递,它就可以在 servlet 端工作。 非常感谢! :) 这完美!我错误地推测,因为 req.setParameter() 不适用于多部分编码,所以 req.getParameter() 也会失败。虽然,我可以确认我在问题中提到的谷歌推荐的方法(使用 ServletFileUpload 和 FileInputStream 的方法)不起作用。【参考方案2】:

据我所知,MultiPartEntityBuilder 负责模拟 enctype="multipart/form-data" 的 html“表单”,然后当您到达 DefaultHttpClient 行时,您只是在发送请求通过 POST 从此表单中。您应该查看实体构建器的文档。它具有将文本字段添加到“表单”[1]的功能。

[1] - http://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/MultipartEntityBuilder.html#addTextBody(java.lang.String,%20java.lang.String)

【讨论】:

谢谢!我遵循了您的建议并更新了我的问题以反映该试验的结果。您能否快速浏览一下并提出任何后续步骤?【参考方案3】:

以防万一,您可能需要指定

entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

创建对象后。

如果这不起作用,建议您在requestbin 上发帖以查看您收到的确切信息

【讨论】:

谢谢哈维尔!设置浏览器兼容模式没有帮助。针对 requestbin 发布确认请求包含参数“param”作为“表单/发布参数”。

以上是关于如何在将 Blob 上传到 Blobstore 的 POST 请求中提交文本字段并在 Blob 的上传处理程序中检索它?的主要内容,如果未能解决你的问题,请参考以下文章

如何从不具有BlobStore的Flask表单直接将视频文件上传到Cloud Storage?

为啥上传图片到 Blobstore 后回调失败?

上传到 Blobstore 会产生 Java 堆 OutOfMemoryError

95-862-040-源码-runtime-blob-BlobStore

Blobstore 图像在 Google App Engine 开发服务器上消失

使用 Google App Engine Blobstore 下载的文件名