When upgrading from Jetty 11 to Jetty 12 I decided to do away with servlets and try the core Jetty libraries. Migration is still in progress but I'm finding that my new REST API server is automatically sending 301 redirects when it receives POST requests over http if the path does not end in a slash /. Strangely the same behavior is not true for GET requests. My question is: is there a way to control 301 redirect behavior in Jetty 12? I looked inside HttConfig and the only option related to redirect seemed to be is/setRelativeRedirectAllowed
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setName("web-server");
// Create a Server instance.
Server server = new Server(threadPool);
// The number of acceptor threads. Used for opening *new* connections. One is probably enough!
int acceptors = 1;
// The number of selectors. Used to juggle active/inactive sockets. For more activity, more selectors may be needed?
int selectors = 1;
// Create a ServerConnector to accept connections from clients.
HttpConnectionFactory httpConfig = new HttpConnectionFactory();
log.debug("Relative redirect allowed: " + httpConfig.getHttpConfiguration().isRelativeRedirectAllowed());
ServerConnector connector = new ServerConnector(server, acceptors, selectors, httpConfig);
connector.setHost("localhost");
connector.setPort(5000);
// The TCP accept queue size. How many new un-connected sockets should we keep around? Prevent DDoS?
connector.setAcceptQueueSize(64);
// Add the Connector to the Server
server.addConnector(connector);
// Initialize handlers
Handler.Sequence topLevelList = new Handler.Sequence();
ContextHandlerCollection apiContext = new ContextHandlerCollection();
topLevelList.addHandler(apiContext);
server.setHandler(topLevelList);
apiContext.addHandler(new ContextHandler(new Handler.Abstract() {
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception {
System.out.println("The request method is: " + request.getMethod());
callback.succeeded();
return true;
}
}, "/api/user/authenticate"));
server.start();
server.join();
And the associated curl command to test:
curl -D - -d '{"key1":"value1", "key2":"value2"}' -H "Content-Type: application/json" -X POST http://localhost:5000/api/user/authenticate
which gives me:
HTTP/1.1 301 Moved Permanently
Server: Jetty(12.0.5)
Date: Thu, 28 Dec 2023 17:14:15 GMT
Location: /api/user/authenticate/
Content-Length: 0
My development team has decided this is not intuitive default behavior! This was a surprise in our migration.
The
ContextHandleryou have is setup at the "Context Path" of/api/user/authenticateA "Context Path" is a root for all behaviors within that specific Context.
So Jetty will automatically append a trailing
/to the "Context Path" to make it sane.I would recommend setting up a
ContextPathat/api.Then using the
PathMappingsHandlerwithin thatContextPathto specify specific endpoints.Something along the lines of ...
You might be interested in using one of the other
PathSpecimplementations too (RegexPathSpecorUriTemplatePathSpec).You can have as many
PathSpecimplementations you want, even mix and match.You can even setup a unit test with
PathMappingsto ensure that the mix of behaviors is operating the way you want.