泽西岛客户端无法指定媒体类型

时间:2015-10-19 12:49:13

标签: java json jersey-2.0 jersey-client

我接到一个休息服务的电话(工作正常),我想改变它并使用球衣。 我从官方网站下载了最后的JAR并将它们放入我的项目中。 我的所有响应抛出异常(除了这个:String response = invocationBuilder.get(String.class);):

javax.ws.rs.NotAcceptableException: HTTP 406 Not Acceptable
    at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1014)
    at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:816)
    at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
    at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:700)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:696)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)

代码:

        ClientConfig clientConfig = new ClientConfig();

        Client client = ClientBuilder.newClient(clientConfig);
        //not so orthodox... 
        WebTarget webTarget = client.target(uri);//uri= https://www.foo.bar/api/v1.0/sms/sendMessage?accessKeyId=34TR&idCampaign=4&fromNumber=Test&toNumber=393281234567&message=Inserisci+la+seguente+password%3A+8c495b

        Invocation.Builder invocationBuilder2 =
                webTarget.request(MediaType.APPLICATION_JSON);
        Invocation.Builder invocationBuilder =
                webTarget.request();//------NO MEDIA TYPE SPECIFICATION
        Invocation.Builder invocationBuilder3 =
                webTarget.request(MediaType.APPLICATION_XML_TYPE);
        Invocation.Builder invocationBuilder4 =
                webTarget.request(MediaType.TEXT_XML_TYPE);
        Invocation.Builder invocationBuilder5 =
                webTarget.request(MediaType.TEXT_PLAIN_TYPE);
        Invocation.Builder invocationBuilder6 =
                webTarget.request(MediaType.APPLICATION_FORM_URLENCODED);

        try {
            String response2 = invocationBuilder2.get(String.class);
        } catch (Exception e) {System.out.println(e);}
        try {
    //WORKS ONLY THIS, WITH NO MEDIA TYPE SPECIFICATION
            String response = invocationBuilder.get(String.class); 
        } catch (Exception e) {System.out.println(e);}
        try {
            String response3 = invocationBuilder3.get(String.class);
        } catch (Exception e) {System.out.println(e);}
        try {
            String response4 = invocationBuilder4.get(String.class);
        } catch (Exception e) {System.out.println(e);}
        try {
            String response5 = invocationBuilder5.get(String.class);
        } catch (Exception e) {System.out.println(e);}
        try {
            String response6 = invocationBuilder6.get(String.class);
        } catch (Exception e) {System.out.println(e);}

//NONE OF THIS WORKS (last part of the test):
        try {
        SmsResponse response02 = invocationBuilder2.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}
        try {
        SmsResponse response0 = invocationBuilder.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}
        try {
        SmsResponse response03 = invocationBuilder3.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}
        try {
        SmsResponse response04 = invocationBuilder4.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}
        try {
        SmsResponse response05 = invocationBuilder5.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}
        try {
        SmsResponse response06 = invocationBuilder6.get(SmsResponse.class);
        } catch (Exception e) {System.out.println(e);}

响应字符串是JSON:{"status":"success","uid":"407077","numSms":1,"errorMsg":false}

但是我在尝试获取 SmsResponse 对象(代码的最后一部分)时遇到异常, response0 抛出了下面的异常(其他情况抛出了之前的406异常) ):

 org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json;charset=UTF-8, type=class it.sian.zfab.SmsResponse, genericType=class it.sian.zfab.SmsResponse.
    at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:808)
    at org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
    at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:700)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:696)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:420)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:316)

豆子:

@XmlRootElement
public class SmsResponse implements Serializable {

    private static final long serialVersionUID = 1L;

    @QueryParam("uid")
    private String uid;

    @QueryParam("status")
    private String status;

    @QueryParam("errorMsg")
    private String errorMsg;

    @QueryParam("numSms")
    private Integer numSms;

    //getter and setter...
}

我的旧方法(有效),在这里您可以看到它与内容应用程序/ json一起正常工作:

private <T> T restCallJson(String uri, Class<T> returnType)
{
    T objectResponse = null;
    try {
        URL url = new URL(uri);
        HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Content-Type", "application/json");

        InputStream inputStream = connection.getInputStream();

        Gson gson = new Gson();
        final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        objectResponse = gson.fromJson(reader, returnType);

        connection.disconnect();            
    }
    catch (Exception e)
    {
        log.error("WebServiceUtility - restCallJson: " + e);
    }
    return objectResponse;
}

1)为什么我不能指定MediaType?我应该使用哪一个?

2)为什么我不能直接检索SmsResponse对象?

1 个答案:

答案 0 :(得分:5)

  

1)为什么我不能指定MediaType?我应该使用哪一个?

request(type)设置Accept: <type>标头。如果服务器未设置为生成类型,则发送的正确响应为406 Not Acceptable

例如request(MediaType.APPLICATION_FORM_URLENCODED)告诉服务器您需要以application/www-x-form-urlencoded形式返回数据。如果服务器无法为端点生成该媒体类型,您将返回406。

如果服务器可以发送JSON,那么request(MediaType.APPLICATION_JSON) 工作。

我要做的是调试,而不是做

String reponse = invocationBuilder.get(String.class);

获取实际的Response对象,并查看标题和响应正文。

Response response = invocationBuilder.get();
int status = response.getStatus();
String body = response.readEntity(String.class);

除了调试之外,这将避免客户端的异常。

这是什么

Invocation.Builder invocationBuilder = webTarget.request();

Accept标头设置为通配符*/*,这意味着服务器可以发送它想要的任何类型。通常你不需要这个,因为客户需要知道它回来的类型才能处理它。你可以做什么来调试,发送通配符请求并获取响应。从那里你可以看到Content-Type标题,看看服务器发回的类型

Invocation.Builder invocationBuilder = webTarget.request();
Response response = invocationBuilder.get();
String contentType = response.getHeaderString("Content-Type");

从那里你可以看到你应该为Accept标题设置什么类型。但是从你的第二个堆栈跟踪看,服务器似乎正在发送application/json,所以request("application/json")没有理由不起作用。

  

2)为什么我不能直接检索SmsResponse对象?

您需要一个可以处理从JSON到SmsResponse的反序列化的JSON提供程序。为此,您可以使用杰克逊提供商。希望你使用Maven。您只需添加此依赖项

即可
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey2.version}</version>
</dependency>

您不需要做任何其他事情。提供者注册自己。如果你没有使用Maven,请告诉我,我会发布你需要的所有罐子。请告诉我你正在使用的泽西版。

<强>除了:

您应该了解Content-TypeAccept之间的差异。当客户端想要告诉服务器它想要什么类型时,它会发送Accept标头。服务器可能无法生成该类型,在这种情况下,您将获得406 Not Acceptable。

客户端使用Content-Type告诉服务器它正在发送什么类型的数据,例如POST,但通常不用于GET,因为GET不发送任何数据。当服务器发回数据时,它总是设置Content-Type响应头以告诉客户端它返回的类型。

您目前使用HttpURLConnection的用法不正确。您应该设置Content-Type标头,而不是Accept标头。它工作正常,因为它只是设置了通配符Accept: */*,而且Gson无论如何也不会关注Content-Type

更新

enter image description here

我刚刚创建了一个新的Maven项目,并且只添加了上面的依赖项。它具有所有上述的传递依赖性。但大多数已经配备泽西岛分销。无论你没有什么,这都是你应该寻找的。主要是杰克逊相关的罐子。