Skip to main content
 首页 » 编程设计

servlets之嵌入式 Jetty 服务器,无法在根上下文下看到网页

2024年07月26日30me-sa

我在具有 3.18.9 内核的 Linux 机器上使用 jetty v9.2.10.v20150310 和 java 版本“1.8.0_45”。

问题是,如果我将上下文路径设置为非根值;即/embed 我可以在嵌入式 jetty 服务器上访问我的网页。但是,如果我将上下文路径设置为根;即“/”我无法访问该页面。有趣的是,当我通过curl 与servlet 交互时,这个问题并没有出现。

这是代码:

final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); 
 
final String servletWebDir = "/"; 
servletHandler.setContextPath( servletWebDir ); 
 
final customServlet iass = new customServlet(); 
 
final ServletHolder servletHolder = new ServletHolder( iass ); 
servletHolder.setInitOrder(0); 
servletHandler.addServlet( servletHolder, "/customServlet" ); 
 
final ResourceHandler resourceHandler = new ResourceHandler(); 
resourceHandler.setDirectoriesListed(false); 
resourceHandler.setResourceBase("."); 
 
final HandlerList handlers = new HandlerList(); 
handlers.setHandlers(new Handler[]{ servletHandler, resourceHandler } ); 
 
server.setHandler( handlers ); 

如果我将 servletWebDir 从“/”更改为“/embed”,一切都会正常工作。 如果没有,我会收到 404。

我可以通过如下的curl命令与servlet成功交互:

curl http://host:8080/customServlet?command=exp

如果我尝试使用http://host:8080/customServlet在 Firefox 或 将 servletWebDir 设置为“/”的 chrome 得到 404。请注意,此代码在 jetty v8.1.16.v20140903 下工作正常。

我做错了什么?我在 Jetty v9.x 中错过了什么?

更新了使用 setBaseResource 并删除 ResourceHandler 的代码:

final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); 
final String servletWebDir = "/"; 
final String theBaseResourceDir = "/aa/bb/cc"; 
Resource theBaseResource = null; 
try{ 
    theBaseResource = Resource.newResource( theBaseResourceDir ); 
} 
catch( MalformedURLException e ){ 
    System.err.println( "setup failed on newResource with the exception " + e.toString() ); 
    System.exit(0); 
} 
 
servletHandler.setBaseResource( theBaseResource ); 
System.err.println("Class path->" + servletHandler.getClassPath() ); 
 
final customServlet iass = new customServlet(); 
final ServletHolder servletHolder = new ServletHolder( iass ); 
servletHolder.setInitOrder(0); 
servletHandler.addServlet( servletHolder, "/customServlet" ); 
final HandlerList handlers = new HandlerList(); 
handlers.setHandlers(new Handler[]{ servletHandler } ); 
server.setHandler( handlers ); 

无论 servletWebDir 的值如何,此新代码都不再向 Web 浏览器提供静态页面。通过curl 与自定义servlet 交互仍然有效。 如果上面的新代码是正确的,我是否错过了什么?类路径在错误日志中报告为 null。接下来我可以尝试什么?

乔金:

我尝试了您建议的代码。我非常感谢您为准备代码示例所花费的时间和精力。然而,代码在运行时失败。错误日志指出:

STDERR: 2015-05-09 15:51:32.278:WARN:/embed:main: 不可用 java.lang.IllegalAccessException:类 org.eclipse.jetty.server.handler.ContextHandler$Context 无法使用修饰符“private”访问类 customServlet 的成员 在 sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)

该异常并未标识应公开的确切成员。 我更新的代码确实有效,而且我不必将一大堆方法从私有(private)更改为公共(public)。

Joakim 能否请您解释一下您的解决方案的好处,如果我没有记错的话,该解决方案需要将私有(private)方法和数据成员更改为公共(public)方法 数据成员和方法,因此失去了封装的一些好处。

修复此问题的更新代码:

server = new Server(); 
final ServerConnector connector = getConnector( server ); 
connector.setReuseAddress(false); 
connector.setSoLingerTime(0); 
 
final int port = 8080; 
connector.setHost( theHostName ); 
connector.setPort( port ); 
 
server.addConnector(connector); 
 
final String theRootContextDir = "/"; 
final ContextHandler rootContext = new ContextHandler(theRootContextDir); 
final String theBaseResourceDir = "."; 
rootContext.setResourceBase( theBaseResourceDir ); 
 
final ResourceHandler rhx = new ResourceHandler(); 
rootContext.setHandler( rhx ); 
 
/** 
  * I want to replace the default jetty error handler with my 
  * custom error handler. However I have not figured out how 
  * to do it under jetty v9.x, yet-(May.08.2015,W.S.) 
  * final ErrorHandler uiErrHandler = new userInputErrorHandler( logger ); 
  * rootContext.setErrorHandler( uiErrHandler ); 
  ***/ 
 
final ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); 
 
final String theServletContextPath = "/"; 
servletHandler.setContextPath( theServletContextPath ); 
servletHandler.setResourceBase( "." ); 
 
final customServlet iass = new customServlet(); 
final ServletHolder servletHolder = new ServletHolder( iass ); 
final MultipartConfigElement mce = new MultipartConfigElement( fileUploadTmpDir ); 
servletHolder.getRegistration().setMultipartConfig( mce ); 
servletHolder.setInitOrder(0); 
final String theServletName = "/customServlet"; 
servletHandler.addServlet( servletHolder, theServletName ); 
 
final HandlerList handlers = new HandlerList(); 
handlers.setHandlers(new Handler[]{ rootContext, servletHandler } ); 
 
server.setHandler( handlers ); 

请您参考如下方法:

您正在使用 ServletContextHandler,不能将其与 ResourceHandler 混合使用,因为 ServletContextHandler 的内置 DefaultServlet 将提供文件(或给出错误响应),使 ResourceHandler 永远不会执行。

修复:

删除ResourceHandler(无论如何,它远不如DefaultServlet)。

设置servletHandler.setBaseResource(Resource)到您的 Web 应用程序根目录(静态文件所在的位置)。这可以是 URL、URI 或文件系统路径引用。

示例:

// As a file system reference 
servletHandler.setBaseResource(Resource.newResource("/path/to/res")); 
 
// or URL 
servletHandler.setBaseResource(Resource.newResource("jar:file://tmp/b.jar!/webroot")); 

资源路径应该指向一个目录,而不是特定的文件。

参见previous answer about this了解更多详情。

示例:

package jetty; 
 
import java.io.File; 
import java.net.MalformedURLException; 
import java.net.URI; 
import java.nio.file.Path; 
 
import org.eclipse.jetty.server.Server; 
import org.eclipse.jetty.servlet.DefaultServlet; 
import org.eclipse.jetty.servlet.ServletContextHandler; 
import org.eclipse.jetty.servlet.ServletHolder; 
import org.eclipse.jetty.util.resource.Resource; 
 
public class SimpleServletExample 
{ 
    public static void main(String[] args) 
    { 
        try 
        { 
            Server server = new Server(8080); 
 
            // Find the full path to the webroot. 
            // Use the real path, with real file system case for all parts of the path 
            // Otherwise we fall afoul of alias checking. 
            // (esp on OSX and Windows. Unix and Linux do not have this issue) 
            Path webrootPath = new File("src/test/resources/sample-files").toPath().toRealPath(); 
 
            URI webrootUri = webrootPath.toUri(); 
 
            System.err.println("webroot uri: " + webrootUri); 
 
            Resource webroot = Resource.newResource(webrootUri); 
            if (!webroot.exists()) 
            { 
                System.err.println("Resource does not exist: " + webroot); 
                System.exit(-1); 
            } 
 
            if (!webroot.isDirectory()) 
            { 
                System.err.println("Resource is not a directory: " + webroot); 
                System.exit(-1); 
            } 
 
            // Establish ServletContext for all servlets 
            ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); 
            context.setContextPath("/"); 
            context.setBaseResource(webroot); 
            // What file(s) should be used when client requests a directory 
            context.setWelcomeFiles(new String[] { "index.html" }); 
            server.setHandler(context); 
 
            // Add a servlet (technique #1) 
            ServletHolder holderHello = context.addServlet(HelloServlet.class,"/hello"); 
            holderHello.setInitOrder(0); 
 
            // Add default servlet last (always last) (technique #2) 
            // Must be named "default", must be on path mapping "/" 
            ServletHolder holderDef = new ServletHolder("default",DefaultServlet.class); 
            holderDef.setInitParameter("dirAllowed","true"); 
            context.addServlet(holderDef,"/"); 
 
            // Start server 
            server.start(); 
        } 
        catch (MalformedURLException e) 
        { 
            System.err.println("Unable to establish webroot"); 
            e.printStackTrace(System.err); 
        } 
        catch (Throwable t) 
        { 
            t.printStackTrace(System.err); 
        } 
    } 
}