使用 Fetch API 通过 React 应用程序调用 servlet - 导致无法加载资源错误(406 - 不可接受)

Invoking servlet through React app using Fetch API - Gives Failed to load Resource error (406 - Not Acceptable)

我对 React JS 和 Java servlet 还很陌生。我在 React 中创建了一个视图,并使用 Jersey 在 servlet 中创建了一个 API 端点。前端和后端都在我本地计算机上的 Tomcat 服务器上 运行。 servlet 尝试访问服务 运行ning http://localhost:37070/expenseClaimService/start 到 post 一个新的声明。此服务已经过单独测试,它 returns 已创建新声明的 id

现在我正尝试使用 Fetch 从 React 应用程序调用 servlet 中的端点。但是我一直在 React 应用程序中收到 Failed to load resource: the server responded with a status of 406

React 应用中的 fetch 调用

  handleAddClaim = () => {
    console.log("in method");
    fetch("http://localhost:8080/eca/api/claims/new-claim", {
      method: "POST",
      headers: {
        Accept: "text/plain",
        "Content-Type": "application/json",
        "Access-Control_Allow-Orign": "*"
      },
      body: JSON.stringify({
        empName: "Test Vendor4",
        empFirstname: "Test",
        empLastname: "Vendor4",
        empEmail: "test4@mail.com",
        empId: "test3",
        empJobTitle: "SE",
        date: "08 December, 2018",
        refNo: "testRef999",
        memo: "OPD test claim 11",
        claims: [
          {
            amount: "9500.00",
            memo: "Test claim - Medicine",
            billDate: "4 December, 2018"
          }
        ]
      })
    })
    .then(response => {
        console.log(response);
    })
    .catch(error => {
        console.error(error);
    });
  };

Servlet 中的端点

@Path("/claims")
public class OPDClaimEndpoint {

    @POST
    @Path("/new-claim")
    @Produces(MediaType.TEXT_HTML)
    @Consumes(MediaType.APPLICATION_JSON)
    public String addNewClaim(JsonObject body){            
        return ExecutionUtils.generatePostRequest(body.toString());
    }
}

正在生成 post 请求(使用 Apache HttpClient)

public static String generatePostRequest(String input){
    String url = "http://localhost:37070/expenseClaimService/start";

    try {
        StringEntity requestEntity = new StringEntity(
                input,
                ContentType.APPLICATION_JSON);

        HttpPost request = new HttpPost(url);
        request.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
        request.setEntity(requestEntity);
        HttpClient client = HttpClientBuilder.create().build();
        HttpResponse response = client.execute(request);
        return response.toString();
    }
    catch ( IOException e) {
        logger.info(e.getMessage());
    }
    return "Failed";
}

web.xml

<servlet>
    <servlet-name>eca-api</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.org.eca.client.api.endpoint</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>eca-api</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

如何解决这个问题,以便我可以从 React 应用程序调用服务? 非常感谢任何帮助。

查看您的 fetch 调用和 Servlet 端点,您的 @Produces 注释指定 servlet 将生成 "text/html" 而 Fetch 调用指定它将仅接受 "text/plain" 类型( "Accept" header).

尝试至少更改其中一项(取决于您的需要)以相互匹配,问题应该得到解决。

您需要发送JSON类型,因此将ACCEPT替换为CONTENT_TYPE

request.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);

与:

request.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);

The HTTP Content-Type header field name.

终于找到解决办法了!

在tomcat日志文件中,可以看出Jersey不支持Gson的JsonObject。

this SO answer indicates, Jersey only supports native types and String as input in their methods. So I changed the endpoint method signature to take in Strings, public String addNewClaim(String body), and now it works even with the bulky Json string. (Note that this is in Jersey 1.19, it may be different in Jersey 2.x). However it can take in Java objects as said in this answer.