JAX-RS/Jersey/TomEE文件上传报HTTP 415错误求助
解决TomEE下JAX-RS文件上传的415 Unsupported Media Type问题
你的问题根源很明确:TomEE默认集成的是Apache CXF作为JAX-RS实现,而你使用的是Jersey的Multipart API,两者之间的冲突导致MultiPartFeature无法正常生效,从而无法处理multipart/form-data请求。Tomcat之所以正常,是因为它本身不自带JAX-RS实现,你的Jersey包可以完全接管请求处理。
下面提供两种可行的解决方案,根据你的需求选择:
方案一:切换到CXF原生Multipart API(推荐,适配TomEE环境)
既然TomEE内置了CXF,直接使用CXF的Multipart组件是最稳妥的方式,避免包冲突:
- 替换依赖:把pom.xml中的Jersey multipart依赖换成CXF的:
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-rs-multipart</artifactId> <version>3.3.6</version> <!-- 版本要和你的TomEE版本匹配,比如TomEE 8对应CXF 3.3.x --> <scope>provided</scope> <!-- TomEE已内置,无需打包到WAR --> </dependency>
- 修改API代码的导入:将Jersey的Multipart相关注解替换为CXF的:
// 替换原来的Jersey导入 import org.apache.cxf.jaxrs.ext.multipart.FormDataContentDisposition; import org.apache.cxf.jaxrs.ext.multipart.FormDataParam; // 其余代码保持不变,@Consumes(MediaType.MULTIPART_FORM_DATA)和方法逻辑无需修改 @Path("/admin/upload") @RequestScoped public class UploadApiImpl { @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFile( @FormDataParam("file") InputStream in, @FormDataParam("file") FormDataContentDisposition info) throws IOException { // 你的文件处理逻辑不变 File upload = new File(info.getFileName()); if (upload.exists()){ String message = "file: " + upload.getName() + " already exists"; return Response.status(Response.Status.CONFLICT).entity(message).build(); } else { Files.copy(in, upload.toPath()); return Response.status(Response.Status.OK).build(); } } @GET public Response uploadFile(){ return Response.status(Response.Status.OK).build(); } }
- 调整配置:
- 如果你用
Application类,继承标准的javax.ws.rs.core.Application而非Jersey的ResourceConfig,确保注册你的API类:import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import java.util.HashSet; import java.util.Set; @ApplicationPath("/mb-portal-service/api/v1") public class MyApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(UploadApiImpl.class); // CXF默认已注册MultipartProvider,无需额外添加 return classes; } } - 如果你用
web.xml,替换为CXF的Servlet配置:<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> <servlet> <servlet-name>CXF JAX-RS Servlet</servlet-name> <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class> <init-param> <param-name>jaxrs.serviceClasses</param-name> <param-value>org.ftc.UploadApiImpl</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXF JAX-RS Servlet</servlet-name> <url-pattern>/mb-portal-service/api/v1/*</url-pattern> </servlet-mapping> </web-app>
- 如果你用
方案二:在TomEE中禁用CXF,强制使用Jersey
如果你坚持使用Jersey,需要让TomEE放弃自带的CXF JAX-RS实现:
- 修改TomEE配置:在TomEE的
conf/system.properties文件中添加以下配置:
openejb.jaxrs.proxy=false openejb.jaxrs.implementation=none
这会禁用TomEE自动加载的CXF JAX-RS组件。
- 恢复Jersey配置:
- 确保pom.xml中保留Jersey的multipart依赖:
<dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-multipart</artifactId> <version>2.27</version> </dependency> - 在你的
Application类中正确注册MultiPartFeature:@ApplicationPath("/mb-portal-service/api/v1") public class Application extends ResourceConfig { public Application() { packages("org.ftc"); this.register(MultiPartFeature.class); // 打开这个注册语句 } } - 或者在
web.xml中确保Jersey的Servlet配置正确:<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>org.ftc</param-value> </init-param> <init-param> <param-name>jersey.config.server.provider.classnames</param-name> <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/mb-portal-service/api/v1/*</url-pattern> </servlet-mapping> </web-app>
- 确保pom.xml中保留Jersey的multipart依赖:
额外注意事项
- 检查TomEE版本与依赖版本的兼容性:比如TomEE 8对应CXF 3.3.x,TomEE 9对应CXF 3.5.x,避免版本不匹配导致的异常。
- 如果你同时使用
web.xml和Application类配置JAX-RS,可能会出现冲突,建议只保留一种配置方式。
内容的提问来源于stack exchange,提问作者Stefan Đogo
相关产品推荐
相关产品推荐

