configure jetty in spring boot - jetty

I am developing a multi-module spring boot project. My project structure look like
myProject(parent)
front-end
src/main/resources
frontend
index.html
rest
src/main/java
com.example
MyWebApp.java
com.example.config
WebAppConfig.java
I am trying to configure jetty by injecting JettyServerCustomizer as bean in WebAppConfig as following
#Bean
public JettyServerCustomizer customizeJettyServer()
{
return new JettyServerCustomizer()
{
#Override
public void customize(final Server server)
{
ContextHandler frontEndContext = new ContextHandler();
frontEndContext.setContextPath(""); //what should be here
frontEndContext.setResourceBase("");//what should be here
ResourceHandler frontEndResourceHandler = new ResourceHandler();
frontEndResourceHandler.setWelcomeFiles(new String[] { "index.html" });
frontEndContext.setHandler(frontEndResourceHandler);
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { frontEndContext});
server.setHandler(contexts);
}
};
}
What value to set to contextPath and ResourceBase so that I could run my index.html which is in front-end module? How the url will looks like?
Thank you :)

Spring Boot can serve static content for you. Instead of trying to configure Jetty, place your static content beneath src/main/resources/static and they'll be loaded straight from the classpath.

Related

Why won't unit tests connect to a websocket

UPDATE: I've uploaded a repo - https://github.com/mrpmorris/CannotIntegrationTestWebApp/blob/master/TestProject1/UnitTest1.cs
I have a web server that serves both HTTPS and WebSocket requests. When I run the app I am able to connect and make requests from postman for both HTTPS://localhost:8080 and WSS://localhost:8080/game-server
using Gambit.ApplicationLayer;
using Gambit.GameServer.Configuration;
using Gambit.GameServer.UseCases;
namespace Gambit.GameServer;
public class Program
{
public static async Task Main(string[] args)
{
WebApplication app = BuildApp(args);
await RunAppAsync(app);
}
public static WebApplication BuildApp(string[] args, Action<WebApplicationBuilder>? configure = null)
{
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
IServiceCollection services = builder.Services;
IConfiguration configuration = builder.Configuration;
IWebHostEnvironment environment = builder.Environment;
services.AddControllers();
services.AddLogging(opts =>
{
opts.ClearProviders();
opts.AddConfiguration(configuration.GetSection("Logging"));
opts.AddDebug();
opts.AddEventSourceLogger();
#if DEBUG
if (environment.IsDevelopment())
opts.AddConsole();
#endif
});
services.Configure<GameServerOptions>(configuration.GetSection("GameServer"));
services.AddApplicationServices(configuration);
configure?.Invoke(builder);
WebApplication app = builder.Build();
return app;
}
public static async Task RunAppAsync(WebApplication app)
{
app.MapGet("/", () => "Gambit.Server.API is running");
app.AddUserUseCases();
app.AddGameUseCases();
app.MapControllers();
app.UseWebSockets();
await app.RunAsync();
}
}
When I run my unit tests I use the same code to create and run the server (once per test run) my tests are able to make HTTPS requests but not connect via a WebSocket. When I try, I get a 404 error. I experience the same in PostMan.
static IntegrationTestsServer()
{
ConfigureMocks();
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTesting");
var app = Program.BuildApp(Array.Empty<string>(), builder =>
{
builder.WebHost.UseSetting("urls", "https://localhost:8080");
});
Configuration = app.Services.GetRequiredService<IConfiguration>();
GameServerOptions = app.Services.GetRequiredService<IOptions<GameServerOptions>>();
var dbContextOptions = app.Services.GetRequiredService<DbContextOptions<ApplicationDbContext>>();
using var dbContext = new ApplicationDbContext(dbContextOptions);
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
HttpClient = new HttpClient { BaseAddress = new Uri("https://localhost:8080") };
_ = Program.RunAppAsync(app);
}
I can even perform a successful HttpClient.GetAsync("https://localhost:8080") immediately before the ClientWebSocket fails
System.Net.WebSockets.WebSocketException : The server returned status code '404' when status code '101' was expected.
Does anyone have any ideas why this might be?
Set ApplicationName in the WebApplicationOptions sent to WebApplication.CreateBuilder
WebApplication.CreateBuilder
(
new WebApplicationOptions
{
ApplicationName = typeof(Gambit.GameServer.Program).Assembly.GetName().Name // <==
}
);
Now it will be able to find your manifest file when running from a test.
See the following blog post for more of the back story on how I figured it out.
https://thefreezeteam.com/posts/StevenTCramer/2022/08/25/runwebserverintest

Binding DeploymentManager to embedded Jetty server

I'm reading the following documentation
regarding the deployment architecture of embedded Jetty, and I tried to configure a very simple jetty server that loads initially without any WebApps or handlers deployed. The server should hot deploy WARs which are copied to a static directory.
My Code:
public class JettyServerDeploymentManager implements JettyServer {
private Server server;
private DeploymentManager deployer;
private AppProvider appProvider;
public void start() throws Exception {
server = new Server(8090);
// Setup Connector
ServerConnector connector = new ServerConnector(server);
server.setConnectors(new Connector[] {connector});
// Handler Tree location for all webapps
ContextHandlerCollection contexts = new ContextHandlerCollection();
// Deployment Management
deployer = new DeploymentManager();
deployer.setContexts(contexts);
appProvider = new WebAppProvider();
((WebAppProvider) appProvider).setMonitoredDirName("/mytmpdir");
deployer.addAppProvider(appProvider);
server.addBean(deployer);
// Handler Tree
HandlerCollection handlers = new HandlerCollection();
handlers.addHandler(contexts);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
server.join();
}
}
This impl should be equivalent to the code provided in the link above (xml configuration).
The server inits without any errors, but when I copy a war file to the scanned directory, nothing happens.
What am I missing? I'm not even sure if the link between my server to the deployment manager is sufficient.
Update:
It seems to be working, at least the scanning part, I've added
static
{
// Make jetty's own logging use java.util.logging
org.eclipse.jetty.util.log.Log.setLog(new JavaUtilLog());
}
And now I see in the logs that the appProvider loads a new war (it fails on NullPtr now)
Apr 08, 2019 2:51:43 PM org.eclipse.jetty.webapp.WebAppContext doStart
WARNING: Failed startup of context o.e.j.w.WebAppContext#19efba8a{/simple1,jar:file:///mytmpdir/simple1.war!/,null}{/mytmpdir/simple1.war}
java.lang.NullPointerException
at org.eclipse.jetty.webapp.MetaInfConfiguration.preConfigure(MetaInfConfiguration.java:77)
at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:501)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:539)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:41)
at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188)
at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:499)
at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:147)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180)
at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:452)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64)
at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610)
at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529)
at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392)
at org.eclipse.jetty.util.Scanner$1.run(Scanner.java:329)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Working solution:
public class JettyServerDeploymentManager implements JettyServer {
private static final Logger log = Logger.getLogger(JettyServerDeploymentManager.class.getName());
private Server server;
private DeploymentManager deployer;
private AppProvider appProvider;
static
{
// Make jetty's own logging use java.util.logging
org.eclipse.jetty.util.log.Log.setLog(new JavaUtilLog());
}
public void start() throws Exception {
server = new Server(8090);
// Setup Connector
ServerConnector connector = new ServerConnector(server);
server.setConnectors(new Connector[] {connector});
// Handler Tree location for all webapps
ContextHandlerCollection contexts = new ContextHandlerCollection();
// Handler Tree
HandlerCollection handlers = new HandlerCollection();
handlers.addHandler(contexts);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
// Deployment Manager
DeploymentManager deploymentManager = new DeploymentManager();
deploymentManager.setContexts(contexts);
// App provider
WebAppProvider appProvider = new WebAppProvider();
appProvider.setExtractWars(true); // required for a proper deployment of inner jars
appProvider.setMonitoredDirName("/mytmpdir");
appProvider.setScanInterval(2);
deploymentManager.addAppProvider(appProvider);
server.addBean(deploymentManager);
log.info("starting server");
server.start();
server.join();
}
private static URL findWebAppPath() {
ClassLoader classLoader = SparkApp.class.getClassLoader();
return classLoader.getResource("");
}

HowTo configure the ErrorPageErrorHandler in embedded Jetty?

Is it possible to configure the ErrorPageErrorHandler in way that it redirects to a static Page if no content/service is found?
Here is my Code:
server = new Server(port);
Resource webRoot = Resource.newResource(webContent);
if (!webRoot.exists()) {
logger.warn("Unable to find root resource:" + webRoot.getName());
} else {
logger.info("Root resource is " + webRoot.getName());
}
ResourceHandler res = new ResourceHandler();
res.setBaseResource(webRoot);
res.setDirAllowed(false);
//servlet handler
ServletContextHandler servletCtx = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletCtx.setContextPath("/service");
servletCtx.addServlet(new ServletHolder("sample", new MyServletSample()), "/sample");
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.addErrorPage(404, "index.html");
servletCtx.setErrorHandler(errorHandler);
// static file handler
ContextHandler staticCtx = new ContextHandler("/");
staticCtx.setBaseResource(webRoot);
staticCtx.setHandler(res);
// add handlers
HandlerList handlerList = new HandlerList();
handlerList.addHandler(servletCtx);
handlerList.addHandler(staticCtx);
// add handerList to server
server.setHandler(handlerList);
This code show me index.html on localhost:8080 and I can access the sample service http://localhost:8080/service/sample. However, I want to show a static error page (i.e. documentation) to show up if an error like "404 Not Found" occured.
With this code, the Error handler logs:
"WARN o.e.j.server.handler.ErrorHandler - No error page found
index.html"
. What is correct way/syntax to define the URI?
Thanks in advance!
This was answered before at https://stackoverflow.com/a/32383973/775715
Don't mix ResourceHandler and ServletContextHandler unless you REALLY know what you are doing, and fully understand the nature of javax.servlet.ServletContext and all of the rules it brings to the table.
See also:
What is difference between ServletContextHandler.setResourceBase and ResourceHandler.setResourceBase when using Jetty embedded container?
Serving static files from alternate path in embedded Jetty
Here's an example of your setup working with NO ResourceHandler, 1 ServletContextHandler, and a DefaultServlet providing the static file serving.
// servlet handler
ServletContextHandler servletCtx = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletCtx.setContextPath("/");
servletCtx.setBaseResource(webRoot); // what static content to serve
servletCtx.setWelcomeFiles(new String[] { "index.html" });
servletCtx.addServlet(new ServletHolder("sample", new MyServletSample()), "/service/sample");
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.addErrorPage(404, "/index.html");
servletCtx.setErrorHandler(errorHandler);
// static file serving, and context based error handling
ServletHolder defaultServ = new ServletHolder("default", DefaultServlet.class);
defaultServ.setInitParameter("dirAllowed","false");
servletCtx.addServlet(defaultServ,"/");
// add handlers
HandlerList handlerList = new HandlerList();
handlerList.addHandler(servletCtx);
handlerList.addHandler(new DefaultHandler()); // non-context error handling

Start embedded Jetty using WebApplicationInitializer

I am creating Restful (Jax-RS) services to be deployed to Fuse 6.2.1.
(using Apache CFX, and deploying with OSGi bundles to Karaf)
The server supports only up to Spring 3.2.12.RELEASE.
I am attempting to do everything with next to zero XML configuration.
So far so good, everything is working and I can deploy and run my services.
However, I'd like to be able to test my services locally without having to deploy them. So I'd like to be able to boostrap a webserver and register my servlet, but can't quite figure our how.
I'm configuring the servlet with this (using Spring's WebApplicationInitializer rather than web.xml):
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public class CxfServletInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
addApacheCxfServlet(servletContext);
}
private void addApacheCxfServlet(ServletContext servletContext) {
CXFServlet cxfServlet = new CXFServlet();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
appServlet.setLoadOnStartup(1);
Set<String> mappingConflicts = appServlet.addMapping("/*");
}
private WebApplicationContext createWebAppContext() {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(CxfServletConfig.class);
return appContext;
}
}
And my main Spring config looks like this:
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.RuntimeDelegate;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
#Configuration
public class CxfServletConfig {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CxfServletConfig.class);
#Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
return new SpringBus();
}
#Bean
#DependsOn("cxf")
public Server jaxRsServer(ApplicationContext appContext) {
JAXRSServerFactoryBean endpoint = RuntimeDelegate.getInstance().
createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
endpoint.setServiceBeans(Arrays.<Object> asList(testSvc()));
endpoint.setAddress(endpoint.getAddress());
endpoint.setProvider(jsonProvider());
return endpoint.create();
}
#Bean
public Application jaxRsApiApplication() {
return new Application();
}
#Bean
public JacksonJsonProvider jsonProvider() {
return new JacksonJsonProvider();
}
#Bean(name = "testSvc")
public TestService testSvc() {
return new TestService();
}
So just to be clear, the above code is my current, working, deployable configuration. So now I'd like to create a test config that utilizes the same but which also starts Jetty and registers my servlet, and can't quite figure out how. Any help?
Thanks!
EDIT: Turns out I did not need the WebApplicationInitializer at all to get this to work. I ended up creating a Test config for Spring that defines a Jetty server as a bean. Seems to work:
#Configuration
public class TestingSpringConfig {
#Bean (name="jettyServer", destroyMethod = "stop")
public Server jettyServer() throws Exception {
Server server = new Server(0); //start jetty on a random, free port
// Register and map the dispatcher servlet
final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );
final ServletContextHandler context = new ServletContextHandler();
context.setContextPath( "/" );
//fuse uses cxf as base url path for cxf services, so doing so as well here so urls are consistent
context.addServlet( servletHolder, "/mybaseurl/*" );
context.addEventListener( new ContextLoaderListener() );
context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
//this will load the spring config for the CFX servlet
context.setInitParameter( "contextConfigLocation", CxfServletConfig.class.getName() );
server.setHandler( context );
server.start();
//server.join(); if running from a main class instead of bean
return server;
}
#Bean(name = "jettyPort")
#DependsOn("jettyServer")
public Integer jettyPort() throws Exception {
Integer port = jettyServer().getConnectors()[0].getLocalPort();
log.info("Jetty started on port: " + port);
return port;
}
}

Cross Origin Filter with embedded Jetty

I'm trying to get a CrossOriginFilter working with a couple of embedded Jetty servers, both running on our internal network. Both are running servlets, but I need server A's web page to be able to post to server B's servlets. I think I need to add ACCESS_CONTROL_ALLOW_ORIGIN to a CrossOriginFilter but finding out how to do this with an embedded Jetty instance with no web.xml isn't proving to be easy. I get the following error message in the browser when trying to access server b's serlvets
No 'Access-Control-Allow-Origin' header is present on the requested resource
Im using angularjs to post to the other server's servlets in a controller.
And here is the code for one of the servers (both are pretty much the same)
Server server = new Server(httpPort);
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[] { "index.html" });
resource_handler.setResourceBase("./http/");
ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(ServerPageRoot.class, "/servlet/*");
FilterHolder holder = new FilterHolder(CrossOriginFilter.class);
holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
handler.addFilter(holder );
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, handler,new DefaultHandler() });
server.setHandler(handlers);
server.start();
A few points:
Don't use ServletHandler naked like that. The ServletHandler is an internal class that ServletContextHandler uses.
The ServletContextHandler is what provides the needed ServletContext object and state for the various servlets and filters you are using.
The ServletContextHandler also provides a place for the overall Context Path declaration
The ServletContextHandler is also the place for Welcome Files declaration.
Don't use ResourceHandler, when you have DefaultServlet available, its far more capable and feature rich.
Example:
Server server = new Server(httpPort);
// Setup the context for servlets
ServletContextHandler context = new ServletContextHandler();
// Set the context for all filters and servlets
// Required for the internal servlet & filter ServletContext to be sane
context.setContextPath("/");
// The servlet context is what holds the welcome list
// (not the ResourceHandler or DefaultServlet)
context.setWelcomeFiles(new String[] { "index.html" });
// Add a servlet
context.addServlet(ServerPageRoot.class,"/servlet/*");
// Add the filter, and then use the provided FilterHolder to configure it
FilterHolder cors = context.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
// Use a DefaultServlet to serve static files.
// Alternate Holder technique, prepare then add.
// DefaultServlet should be named 'default'
ServletHolder def = new ServletHolder("default", DefaultServlet.class);
def.setInitParameter("resourceBase","./http/");
def.setInitParameter("dirAllowed","false");
context.addServlet(def,"/");
// Create the server level handler list.
HandlerList handlers = new HandlerList();
// Make sure DefaultHandler is last (for error handling reasons)
handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
server.setHandler(handlers);
server.start();
managed to get it working by doing
FilterHolder holder = new FilterHolder(CrossOriginFilter.class);
holder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
holder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin");
holder.setName("cross-origin");
FilterMapping fm = new FilterMapping();
fm.setFilterName("cross-origin");
fm.setPathSpec("*");
handler.addFilter(holder, fm );
Maybe this will help someone even though it is not a good answer to the original question. I realized that you can easaly enable cross origin request sharing in an embedded jetty instance by manipulating the headers directly in your handler. The response object below is an instance of HttpServletResponse (which is passed to the handler).
Example:
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", "POST, GET");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
I tried all the way of above answers and other similar ones. But always, I came across same error message.
Finally I reach a correct answer for my situation. I use Jersey with Jetty and I am not using web.xml. If you try all methods and you don't enable the CORS support, maybe you can try this solution below.
First, define a filter (you can define another one which directly implements Filter class)
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null && request.getMethod().equalsIgnoreCase("OPTIONS");
}
#Override
public void filter(ContainerRequestContext request) throws IOException {
// If it's a preflight request, we abort the request
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
// if there is no Origin header, we don't do anything.
if (request.getHeaderString("Origin") == null) {
return;
}
// If it is a preflight request, then we add all
// the CORS headers here.
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
// Whatever other non-standard/safe headers (see list above)
// you want the client to be able to send to the server,
// put it in this list. And remove the ones you don't want.
"X-Requested-With,Content-Type,Content-Length,Authorization,"
+ "Accept,Origin,Cache-Control,Accept-Encoding,Access-Control-Request-Headers,"
+ "Access-Control-Request-Method,Referer,x-csrftoken,ClientKey");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
Register this filter to resource config
import java.io.IOException;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
public class AppServer {
public static void main(String[] args) throws Exception {
Server jettyServer = new Server();
// Add port
ServerConnector jettyServerConnector = new ServerConnector(jettyServer);
jettyServerConnector.setPort(Integer.parseInt("9090"));
jettyServer.addConnector(jettyServerConnector);
// Define main servlet context handler
ServletContextHandler jettyServletContextHandler = new ServletContextHandler();
jettyServletContextHandler.setContextPath("/service");
// Define main resource (webapi package) support
ResourceConfig webapiResourceConfig = new ResourceConfig();
webapiResourceConfig.packages("com.example.service");
ServletContainer webapiServletContainer = new ServletContainer(webapiResourceConfig);
ServletHolder webapiServletHolder = new ServletHolder(webapiServletContainer);
jettyServletContextHandler.addServlet(webapiServletHolder, "/webapi/*");
// Add Cors Filter
webapiResourceConfig.register(CorsFilter.class, 1);
try {
jettyServer.start();
jettyServer.dump(System.err);
jettyServer.join();
} catch (Throwable t) {
t.printStackTrace(System.err);
} finally {
jettyServer.destroy();
}
}
}
That's it. This solution solved my problem. Maybe it can be useful for others.