You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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并注册自定义处理器的方式绕开这个限制:

  1. 先创建一个自定义的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);
        }
    }
}
  1. 然后修改你的SpecificRestAPImain方法,不用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的例子:

  1. 定义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等
}
  1. 启动端点(用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

火山引擎 最新活动