Tomcat 9下JAX-RS服务Ajax POST请求跨域报错求助
Ah, classic CORS gotcha! Postman works because it skips sending the preflight OPTIONS request that browsers automatically trigger for cross-origin requests (especially POST requests with custom headers or content types). Let's walk through the most reliable fixes for your JAX-RS + Tomcat 9 setup:
This is a code-level fix that gives you fine-grained control over CORS rules for your API. Create a filter class that adds the required headers to every response:
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; import java.io.IOException; @Provider public class CorsFilter implements ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { // Replace "*" with your frontend's actual domain in production (e.g., "https://your-app.com") responseContext.getHeaders().add("Access-Control-Allow-Origin", "*"); responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true"); responseContext.getHeaders().add("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization"); responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); } }
Next, make sure this filter is registered with your JAX-RS application:
- If you're using a
ResourceConfigclass, addregister(CorsFilter.class)to its constructor. - If you're configuring via
web.xml, add the filter's fully qualified class name to the<init-param>of your JAX-RS servlet underjavax.ws.rs.Applicationorjersey.config.server.provider.classnames.
You'll also need to handle OPTIONS preflight requests (browsers send these before the actual POST). Add a generic OPTIONS endpoint to catch all such requests:
import javax.ws.rs.OPTIONS; import javax.ws.rs.Path; import javax.ws.rs.core.Response; @Path("/") public class CorsOptionsHandler { @OPTIONS @Path("{path:.*}") public Response handleOptionsRequests() { return Response.ok().build(); } }
If you don't want to modify your API code, you can enable CORS globally for all apps on your Tomcat server. Edit conf/web.xml (in your Tomcat installation directory) and add these entries:
<filter> <filter-name>CorsFilter</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> <init-param> <param-name>cors.allowed.origins</param-name> <param-value>*</param-value> <!-- Replace with your frontend domain in production --> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,PUT,DELETE,OPTIONS</param-value> </init-param> <init-param> <param-name>cors.allowed.headers</param-name> <param-value>Origin, Content-Type, Accept, Authorization</param-value> </init-param> <init-param> <param-name>cors.support.credentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Restart Tomcat after making this change, and all your applications will automatically handle CORS preflight requests.
If you're using a specific JAX-RS implementation like Jersey, it has built-in CORS support you can leverage. For Jersey:
Register the CorsFilter in your ResourceConfig:
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.filter.CorsFilter; public class MyApiApplication extends ResourceConfig { public MyApiApplication() { register(CorsFilter.class); // Register your API resources here } }
Then configure CORS rules via web.xml init params:
<servlet> <servlet-name>MyApi</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.yourpackage.MyApiApplication</param-value> </init-param> <init-param> <param-name>jersey.config.server.cors.allowedOrigins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>jersey.config.server.cors.allowedMethods</param-name> <param-value>GET,POST,PUT,DELETE,OPTIONS</param-value> </init-param> </servlet>
Important Notes for Production
- Never use
*forAccess-Control-Allow-Originin production. Replace it with your frontend's exact domain (e.g.,https://your-frontend.com). - If your frontend sends credentials (like cookies),
Access-Control-Allow-Originmust be a specific domain (not*), andAccess-Control-Allow-Credentialsmust be set totrue.
内容的提问来源于stack exchange,提问作者zahif

