使用javax.xml.ws.Endpoint创建REST端点时PATCH请求无法处理的问题
咱们先明确问题根源:你用的JAX-WS内置WSHttpHandler硬编码只支持GET/POST/HEAD/PUT/DELETE这几种HTTP方法,完全没把PATCH放进判断条件里,所以才会抛出警告并返回空响应。下面针对你的两个选项逐一给出解决方案:
选项a:替换自定义WSHttpHandler?可行但有门槛
直接替换JDK内置的WSHttpHandler难度很高,因为它属于JDK内部API(com.sun.xml.internal.ws包下),JAX-WS的Endpoint默认发布机制没有提供公开的扩展点让你替换这个Handler。不过可以通过手动创建HttpServer并注册自定义处理器的方式绕开这个限制:
- 先创建一个自定义的
HttpHandler,在里面放行PATCH方法,再委托给JAX-WS的原生适配器处理:
import com.sun.xml.internal.ws.transport.http.server.ServerAdapter; import com.sun.xml.internal.ws.transport.http.server.ServerAdapterList; import com.sun.xml.internal.ws.transport.http.server.WSHttpHandler; import com.sun.xml.internal.ws.transport.http.HttpAdapter; import com.sun.xml.internal.ws.api.server.WSEndpoint; import javax.xml.ws.Endpoint; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.net.InetSocketAddress; public class CustomHttpHandler implements HttpHandler { private final WSHttpHandler delegateHandler; public CustomHttpHandler(WSEndpoint<?> endpoint) { ServerAdapterList adapterList = new ServerAdapterList(); ServerAdapter adapter = new ServerAdapter("/specificrestapi", endpoint, adapterList); this.delegateHandler = new WSHttpHandler(adapter); } @Override public void handle(HttpExchange exchange) throws IOException { String method = exchange.getRequestMethod().toUpperCase(); // 放行PATCH方法,其他方法交给原生Handler处理 if ("PATCH".equals(method)) { // 直接调用适配器处理请求 ((HttpAdapter) delegateHandler.getAdapter()).handle(new com.sun.xml.internal.ws.transport.http.server.ServerConnectionImpl((ServerAdapter) delegateHandler.getAdapter(), exchange)); } else { delegateHandler.handle(exchange); } } }
- 然后修改你的
SpecificRestAPI的main方法,不用Endpoint.publish(),而是手动启动HttpServer并注册自定义Handler:
public static void main(String[] args) throws IOException { String url = args[0]; // 比如"http://localhost:9902" InetSocketAddress address = new InetSocketAddress(9902); HttpServer server = HttpServer.create(address, 0); // 创建JAX-WS端点 Endpoint endpoint = Endpoint.create(new SpecificRestAPI()); // 注册自定义Handler server.createContext("/specificrestapi", new CustomHttpHandler(endpoint.getEndpoint())); server.start(); System.out.println("Endpoint started at " + url); }
⚠️ 注意:这种方法依赖JDK内部API,不同JDK版本(比如OpenJDK vs Oracle JDK,或者不同大版本)可能会有兼容性问题,后续升级JDK时需要注意。
选项b:改用更现代的REST实现(更推荐)
其实JAX-WS本身是为SOAP服务设计的,用来做REST属于“用错了工具”,这也是为什么它对PATCH这类REST常用方法支持不好。更推荐的方案是:
方案1:使用JAX-RS框架(专门的REST标准)
比如Jersey(GlassFish官方实现)、RESTEasy(WildFly/JBoss实现),它们天然支持所有HTTP方法包括PATCH,而且开发REST服务更简洁。举个Jersey的例子:
- 定义REST资源类:
import javax.ws.rs.PATCH; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Response; @Path("/specificrestapi") public class SpecificRestAPI { @PATCH public Response processPatch(@QueryParam("do") String action) { // 处理PATCH请求逻辑 return Response.ok("Handled PATCH action: " + action).build(); } // 其他方法比如DELETE、GET等 }
- 启动端点(用Jersey的HttpServerFactory):
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory; import org.glassfish.jersey.server.ResourceConfig; import java.net.URI; public class Main { public static void main(String[] args) { URI baseUri = URI.create("http://localhost:9902/"); ResourceConfig config = new ResourceConfig(SpecificRestAPI.class); JdkHttpServerFactory.createHttpServer(baseUri, config); System.out.println("REST endpoint started at " + baseUri); } }
方案2:使用Spring Boot Web
如果你的项目已经在使用Spring,或者想快速搭建REST服务,Spring Boot Web是更简单的选择,它对PATCH方法支持完美:
import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class SpecificRestController { @PatchMapping("/specificrestapi") public String processPatch(@RequestParam("do") String action) { return "Handled PATCH action: " + action; } }
启动类直接用@SpringBootApplication注解,运行即可,不需要手动处理服务器配置。
方案3:升级JAX-WS实现到Metro最新版
如果你坚持要用JAX-WS做REST,可以试试升级到GlassFish的Metro JAX-WS RI(替代JDK内置的实现),新版本的Metro已经支持PATCH方法了。你需要在项目中引入Metro的依赖,然后配置使用它的端点发布机制,而不是JDK内置的。
内容的提问来源于stack exchange,提问作者simonalexander2005




