Google App引擎:NullpointerException,同时通过Java servlet将图像存储在Blobstore中

|| 我正在尝试通过JSP文件上传和验证Servlet将图片上传到Blobstore。 JSP部分如下:
<form action=\"/testuploadmimevalidation?provider-key=testprovider\" method=\"post\" enctype=\"multipart/form-data\">
    <input type=\"text\" name=\"foo\">
    <input type=\"file\" name=\"myfile\" >
    <input type=\"submit\" value=\"Submit\">
</form>
Java类
TestUploadMimeValidation
如下:
public class TestUploadMimeValidation extends HttpServlet {

    private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    private static final Logger log = Logger.getLogger(TestUploadMimeValidation.class.getName());
    private static final boolean PRODUCTION_MODE = SystemProperty.environment.value() == SystemProperty.Environment.Value.Production;
    private static final String URL_PREFIX = PRODUCTION_MODE ? \"\" : \"http://127.0.0.1:8080\";

    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        InputStream in = req.getInputStream();
        int formDataLength = req.getContentLength();
        byte dataBytes[] = new byte[formDataLength];
        int len;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        while ((len = in.read(dataBytes, 0, formDataLength)) != -1)
            bos.write(dataBytes, 0, len);

        dataBytes = bos.toByteArray();
        String urlStr = URL_PREFIX + BlobstoreServiceFactory.getBlobstoreService().createUploadUrl(\"/testupload\");
        URLFetchService urlFetch = URLFetchServiceFactory.getURLFetchService();
        HTTPRequest request = new HTTPRequest(new URL(urlStr), HTTPMethod.POST, FetchOptions.Builder.withDeadline(20.0));
        request.setHeader(new HTTPHeader(\"Content-Type\", \"multipart/form-data\"));
        request.setPayload(dataBytes);

        System.out.println(\"step1\");

        try {
            HTTPResponse response = urlFetch.fetch(request);
            System.out.println(\"step2\");
        } catch (IOException e) {

        } catch (NullPointerException e) {

        }

        System.out.println(\"step3\");
    }
}
这个类将图像上传到Blobstore很好,但是我得到了3英镑。 stacktrace如下:
WARNING: /_ah/upload/ag5tOGJ5dXMtZGV2ZWxvcHIbCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGAIM
java.lang.NullPointerException
        at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:143)
        at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:180)
        at com.google.appengine.api.blobstore.dev.UploadBlobServlet.access$000(UploadBlobServlet.java:72)
        at com.google.appengine.api.blobstore.dev.UploadBlobServlet$1.run(UploadBlobServlet.java:101)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.google.appengine.api.blobstore.dev.UploadBlobServlet.doPost(UploadBlobServlet.java:98)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
        at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
        at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
        at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
        at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
        at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
        at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
        at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
        at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
        at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
        at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
        at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
        at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:351)
        at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
        at org.mortbay.jetty.Server.handle(Server.java:326)
        at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
        at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
        at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
        at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
        at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
        at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
由于这个NPE,我的
TestUpload.java
类中的代码无法执行。六英镑出来很好。它打印\“ step3 \”。图像将存储到数据存储中。但是我只是无法获得
TestUpload
中的代码来运行。您是否知道可能导致异常的原因?我曾尝试弄乱多部分内容,但不是很成功。 对此问题的任何帮助将不胜感激。     
已邀请:
我用
<form action=\"<%= blobstoreService.createUploadUrl(\"/catalog/actions/add\") %>\" method=\"post\" enctype=\"multipart/form-data\" >
    
首先,您可以在此处查看如何执行POST请求: 使用java.net.URLConnection触发和处理HTTP请求
String param = \"value\";
File textFile = new File(\"/path/to/file.txt\");
File binaryFile = new File(\"/path/to/file.bin\");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just
// generate some unique random value.
String CRLF = \"\\r\\n\"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty(\"Content-Type\",
    \"multipart/form-data; boundary=\" + boundary);
PrintWriter writer = null;
try {
    OutputStream output = connection.getOutputStream();
    writer = new PrintWriter(new OutputStreamWriter(output, charset),
            true); // true = autoFlush, important!
    // Send normal param.
    writer.append(\"--\" + boundary).append(CRLF);
    writer.append(\"Content-Disposition: form-data; name=\\\"param\\\"\")
            .append(CRLF);
    writer.append(\"Content-Type: text/plain; charset=\" + charset).append(CRLF);
    writer.append(CRLF);
    writer.append(param).append(CRLF).flush();
    // Send text file.
    writer.append(\"--\" + boundary).append(CRLF);
    writer.append(
        \"Content-Disposition: form-data; name=\\\"textFile\\\"; filename=\\\"\"
            + textFile.getName() + \"\\\"\").append(CRLF);
    writer.append(\"Content-Type: text/plain; charset=\" + charset).append(CRLF);
    writer.append(CRLF).flush();
    BufferedReader reader = new BufferedReader(new InputStreamReader(
            new FileInputStream(textFile), charset));
    try {
        for (String line; (line = reader.readLine()) != null;) {
            writer.append(line).append(CRLF);
        }
    } finally {
        try { reader.close(); } catch (IOException logOrIgnore) {}
    }
    writer.flush();
    // Send binary file.
    writer.append(\"--\" + boundary).append(CRLF);
    writer.append(
        \"Content-Disposition: form-data; name=\\\"binaryFile\\\"; filename=\\\"\"
            + binaryFile.getName() + \"\\\"\").append(CRLF);
    writer.append(
        \"Content-Type: \"
            + URLConnection.guessContentTypeFromName(binaryFile
                .getName())).append(CRLF);
    writer.append(\"Content-Transfer-Encoding: binary\").append(CRLF);
    writer.append(CRLF).flush();
    InputStream input = new FileInputStream(binaryFile);
    try {
        byte[] buffer = new byte[1024];
        for (int length = 0; (length = input.read(buffer)) > 0;) {
            output.write(buffer, 0, length);
        }
        output.flush(); // Important! Output cannot be closed. Close of
                        // writer will close output as well.
    } finally {
        try { input.close(); } catch (IOException logOrIgnore) {}
    }
    writer.append(CRLF).flush(); // CRLF is important! It indicates end
                                    // of binary boundary.
    // End of multipart/form-data.
    writer.append(\"--\" + boundary + \"--\").append(CRLF);
} finally {
    if (writer != null) writer.close();
}
我尝试使用apache http-client库,但它只能在本地工作。由于套接字限制,我们不能使用它。 https://developers.google.com/appengine/docs/java/sockets/#limitations-and-restrictions 我们坚持使用: java.net.URL; java.net.URLConnection; 对于图像,请使用上面链接中的二进制文件。直到我得到工作代码,这才让我痛苦不已:)     
TL; DR:对于那些尝试使用AJAX而不是传统的表单提交路径时出现此特别奇怪的错误的人,解决方案是在创建AJAX请求时不设置\“ Content-Type \”标头。删除后,它开始为我工作。 更多信息:显然,将FormData对象作为AJAX请求的主体传递,将自动为\“ Content-Type \”标头设置\\“ multipart / form-data \”,以及所需的边界字符串(即如果我们自己设置内容类型,则会丢失)。 附加信息:此边界字符串是AFAIK,是随机生成的,我们无法通过\“ Content-Type \”标头定义自己的边界(我已经尝试过,并且主体中使用的边界仍然是随机生成的字符串,导致堆空间错误)。 AJAX请求必须在标头中分配随机生成的边界字符串,并且设置我们自己的内容类型将覆盖该标头。 我从这里得到了线索:ajax上的html表单enctype(尽管与jQuery相关,但是设置Content-type标头的逻辑是本机webkit /浏览器逻辑)     

要回复问题请先登录注册