问题描述
我正在具有3.18.9内核的Linux机器上使用Java版本为"1.8.0_45"的jetty v9.2.10.v20150310.
I am using jetty v9.2.10.v20150310 with java version "1.8.0_45" on a linux box with a 3.18.9 kernel.
问题是,如果我将上下文路径设置为非根值;即,/embed我可以在嵌入式码头服务器上访问我的网页.但是,如果我将上下文路径设置为root;即"/",我无法访问该页面.有趣的是,当我通过curl与servlet交互时,这个问题没有出现.
The problem is that if I set the context path to a non root value; i.e., /embed I can access my web page on my embedded jetty server. However if I set the context path to root; i.e., "/" I cannot access the page. Interestingly this problem does not show up when I interact with the servlet via curl.
这是代码:
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.
If I change servletWebDir from "/" to "/embed" everything works as it should.If not I get a 404.
我可以通过以下curl命令与servlet成功交互:
I can interact successfully with the servlet via curl commands a follows:
如果我尝试在firefox或Firefox中使用 http://host:8080/customServlet chrome,servletWebDir设置为"/",我得到一个404.请注意,此代码在码头v8.1.16.v20140903下可以正常工作.
If I attempt to use http://host:8080/customServlet in either firefox orchrome with servletWebDir set to "/" I get a 404. Note that this code works fine under jetty v8.1.16.v20140903.
我做错了什么?我在Jetty v9.x中错过了什么?
What am I doing wrong? What have I missed in 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交互仍然有效.如果上面的新代码正确,我错过了什么吗?在错误日志中,类路径被报告为空.我接下来可以尝试什么?
This new code no longer serves a static page to a web browser regardless of the value of servletWebDir. Interacting with the custom servlet via curl still works.If the above new code is correct have I missed something? The class path is reported as null in the error logs. What can I try next?
Joakim:
我尝试了您建议的代码.我非常感谢您准备代码示例所花费的时间和精力.但是,代码在运行时失败.错误日志状态:
I tried the code you suggested. I really appreciate the time and effort you took to prepare the code sample. However the code fails at run time. The error log states:
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)
STDERR: 2015-05-09 15:51:32.278:WARN:/embed:main: unavailablejava.lang.IllegalAccessException: Class org.eclipse.jetty.server.handler.ContextHandler$Context can not access a member of class customServlet with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
该异常未标识应公开的确切成员.我更新的代码可以正常工作,而不必将一整套方法从私有更改为公开.
The exception does not identify the exact member that should be made public.My updated code does work and I do not have to change a whole bunch of methods from private to public.
Joakim,请您解释一下您的解决方案的好处,如果我没记错的话,您需要将私有方法和数据成员更改为公开数据成员和方法,因此失去了封装的某些好处.
Joakim could you please explain the benefits of your solution which, if I am not mistaken, requires changing private methods and data members to publicdata members and methods and therefore losing some of the benefits of encapsulation.
已更新的可解决此问题的代码:
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
永远不会执行.
You are using a ServletContextHandler
, you cannot mix that with a ResourceHandler
, as the built-in DefaultServlet
of the ServletContextHandler
will serve the files (or give an error response), leaving the ResourceHandler
to never execute.
要修复:
拖放ResourceHandler
(无论如何,它都远低于DefaultServlet
).
Drop the ResourceHandler
(its far inferior to the DefaultServlet
anyway).
设置 servletHandler.setBaseResource(Resource)
到您的Web应用程序根目录(您的静态文件所在的目录).这可以是URL,URI或文件系统路径引用.
Set the servletHandler.setBaseResource(Resource)
to your web application root directory (where your static files are). This can be a URL, URI, or file system path reference.
示例:
// As a file system reference
servletHandler.setBaseResource(Resource.newResource("/path/to/res"));
// or URL
servletHandler.setBaseResource(Resource.newResource("jar:file://tmp/b.jar!/webroot"));
资源路径应指向目录,而不是特定文件.
The resource path should point to a directory, not a specific file.
有关更多详细信息,请参见有关此问题的先前答案.
See previous answer about this for more details.
示例:
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);
}
}
}
这篇关于嵌入式Jetty服务器,在根上下文下看不到网页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!