【问题标题】:Jetty :Illegal State exception - No multipart config for servlet码头:非法状态异常 - servlet 没有多部分配置
【发布时间】:2020-06-23 11:27:54
【问题描述】:

将 Jetty 更新到 9.4.21 并将 servlet 更新到 3.1 后,以下代码停止工作。在 getParts 中出现错误。

    req.setAttribute("org.eclipse.multipartConfig", new MultipartConfigElement(System.getProperty("java.io.tmpdir")));
    Part filePart = null;
    try
    {
        
        filePart = getFilePart(req);
        
        try (BufferedInputStream in = new BufferedInputStream(filePart.getInputStream()))
        {
            processFileUploadRequest(req, res, in);
        }
        
    }

例外:

java.lang.IllegalStateException: No multipart config for servlet
at org.eclipse.jetty.server.Request.getParts(Request.java:2321)
at org.eclipse.jetty.server.Request.getParts(Request.java:2309)
at com.siemens.t3k.hmi.jetty.FileUploadServlet.getFilePart(FileUploadServlet.java:126)
at com.siemens.t3k.hmi.jetty.FileUploadServlet.doPost(FileUploadServlet.java:77)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:760)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:547)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)

这里有什么问题?

【问题讨论】:

  • 如果你有一个 Servlet,你为什么要在代码中这样做?并且不使用@MultipartConfig(servlet 注释)或WEB-INF/web.xml 中的<multipart-config>(或在embedded-jetty 中添加servlet 时声明MultipartConfigElement)?

标签: java jetty multipart embedded-jetty


【解决方案1】:

首先,不要在原始文件中使用ServletHandler

这是ServletContextHandler 的内部类,不能直接使用。

接下来,使用ServletContextHandler 适当地拥有一个您的servlet 可以使用的健全的javax.servlet.ServletContext

当您将FileUploadServlet 添加到ServletContextHandler 时,请在此时声明MultipartConfigElement

例子:

package jetty.multipart;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.MultiPartFormDataCompliance;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;

import static java.nio.charset.StandardCharsets.UTF_8;

public class SOFileUploadDemo
{
    public static void main(String[] args) throws Exception
    {
        Server server = new Server();

        HttpConfiguration httpConf = new HttpConfiguration();
        // Use the standard parser for multipart/mime
        httpConf.setMultiPartFormDataCompliance(MultiPartFormDataCompliance.RFC7578);

        // Establish the HTTP ServerConnector
        ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConf));
        httpConnector.setPort(8080);
        server.addConnector(httpConnector);

        ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
        contextHandler.setContextPath("/");
        // Establish output directory
        Path outputDir = Paths.get("target/upload-dir");
        ensureDirExists(outputDir);

        ServletHolder uploadHolder = new ServletHolder(new FileUploadServlet(outputDir));

        // MultiPartConfig setup - to allow for ServletRequest.getParts() usage
        Path multipartTmpDir = Paths.get("target/multipart-tmp");
        ensureDirExists(multipartTmpDir);

        String location = multipartTmpDir.toString();
        long maxFileSize = 10 * 1024 * 1024; // 10 MB
        long maxRequestSize = 10 * 1024 * 1024; // 10 MB
        int fileSizeThreshold = 64 * 1024; // 64 KB
        MultipartConfigElement multipartConfig = new MultipartConfigElement(location, maxFileSize, maxRequestSize, fileSizeThreshold);

        uploadHolder.getRegistration().setMultipartConfig(multipartConfig);
        contextHandler.addServlet(uploadHolder, "/upload/*");

        server.setHandler(contextHandler);

        server.start();
        System.out.println("You can find the server at " + server.getURI());
        server.join();
    }

    private static Path ensureDirExists(Path path) throws IOException
    {
        Path dir = path.toAbsolutePath();

        if (!Files.exists(dir))
        {
            Files.createDirectories(dir);
        }

        return dir;
    }

    public static class FileUploadServlet extends HttpServlet
    {
        private final Path outputDir;

        public FileUploadServlet(Path outputDir)
        {
            this.outputDir = outputDir;
        }

        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
        {
            response.setContentType("text/plain");
            response.setCharacterEncoding("utf-8");

            PrintWriter out = response.getWriter();

            for (Part part : request.getParts())
            {
                out.printf("Got Part[%s].size=%s%n", part.getName(), part.getSize());
                out.printf("Got Part[%s].contentType=%s%n", part.getName(), part.getContentType());
                out.printf("Got Part[%s].submittedFileName=%s%n", part.getName(), part.getSubmittedFileName());
                String filename = part.getSubmittedFileName();
                if (StringUtil.isNotBlank(filename))
                {
                    // ensure we don't have "/" and ".." in the raw form.
                    filename = URLEncoder.encode(filename, UTF_8);

                    Path outputFile = outputDir.resolve(filename);
                    try (InputStream inputStream = part.getInputStream();
                         OutputStream outputStream = Files.newOutputStream(outputFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))
                    {
                        IO.copy(inputStream, outputStream);
                        out.printf("Saved Part[%s] to %s%n", part.getName(), outputFile.toString());
                    }
                }
            }
        }
    }
}

如果您运行该代码并使用curl 对其进行测试,您会得到...

$ curl -v -F key1=value1 -F upload=@image.png http://localhost:8080/upload/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /upload/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 130684
> Content-Type: multipart/form-data; boundary=------------------------4a0d7cd4df695240
> Expect: 100-continue
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Tue, 23 Jun 2020 14:22:17 GMT
< Content-Type: text/plain;charset=utf-8
< Content-Length: 255
< Server: Jetty(9.4.30.v20200611)
< 
Got Part[key1].size=6
Got Part[key1].contentType=null
Got Part[key1].submittedFileName=null
Got Part[upload].size=130397
Got Part[upload].contentType=image/png
Got Part[upload].submittedFileName=image.png
Saved Part[upload] to target/upload-dir/image.png
* Connection #0 to host localhost left intact

你可以看到target/upload-dir产生的文件

$ ls -la target/upload-dir/
total 136
drwxrwxr-x 2 joakim joakim   4096 Jun 23 09:22 ./
drwxrwxr-x 8 joakim joakim   4096 Jun 23 09:20 ../
-rw-rw-r-- 1 joakim joakim 130397 Jun 23 09:22 image.png

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多