使用JAX-RS Jersey 2.2进行Content-Type和Accept头的GET请求

17
我尝试访问一个提供交通信息的开放数据网络服务。文档说明请求必须为 GET,并且需要包含 Accept: application/jsonContent-Type: application/json。我不理解为什么他们需要 Content-Type,但是好吧:

我已经尝试只使用 Accept: 标头来检索数据,但我一直收到 415 Unsupported Media Type 的错误。现在我正在尝试这种方式(但我不确定是否正确设置了两个标头):
String entity = ClientBuilder.newClient().target(liveDataURI)
    .path(liveDataPath)
    .request(MediaType.APPLICATION_JSON)
    .accept(MediaType.APPLICATION_JSON)
    .get(String.class);

您看到我正在使用Jersey 2.2,但仍然收到“415 Unsupported Media Type”错误。

编辑

所以我让它工作了,但我不明白为什么。 accept(MediaType.APPLICATION_JSON)header("Content-type","application/json") 不是一样的吗?

String responseEntity = ClientBuilder.newClient()
    .target(liveDataURI)
    .path(liveDataPath)
    .request(MediaType.APPLICATION_JSON)
    .header("Content-type", "application/json")
    .get(String.class);
3个回答

21

Accept头告诉服务器客户端想要在响应中得到什么。而Content-Type头则告诉服务器客户端在请求中发送了什么。因此,这两者是不同的

如果服务器只接受application/json,那么你必须发送一个指定请求内容的请求:

Content-Type: application/json

这就是为什么你编辑后的代码能够工作的原因。

编辑

在你的第一段代码中,你使用了 WebTarget.request(MediaType... acceptedResponseTypes)。这个方法的参数

定义了可接受的响应媒体类型。

你在这个方法调用的结果上使用了 Innvocation.Builder.accept(MediaType... mediaTypes)。但是 accept() 没有添加新的头信息,在你的第一段代码中是不必要的。

你从未指定请求的内容类型。由于服务器期望一个 Content-Type 头信息,它会响应 415


1
好的,我明白了!但是顺便说一下:我没有发送任何东西到服务器上,我只是进行请求,那么为什么Content-type还是必要的呢?把我发送的参数计算为“content”吗? - Shady
什麼參數?我不知道為什麼這個伺服器在 GET 請求中需要 Content-Type。您必須詢問運行此伺服器的人 :) - user1907906
我可以在URI中指定一些参数来请求。但不管怎样,非常感谢! - Shady
请求中的 Accept 标头告诉服务器客户端希望在响应中得到什么。响应中的 Content-Type 标头告诉客户端服务器发送了什么响应。因此这两者并不相同。 - Roshan
1
在请求头中,Accept 适用于响应正文,而 Content-Type 适用于请求正文。请参阅 HTTP 请求头列表 - Guillaume Husta

18

accept(MediaType.APPLICATION_JSON)header("Content-type","application/json")不是相同的。

以下是它们之间的关系:

Client                     Server
(header)                   (class/method annotation)
====================================================
Accept          <--->      @Produces
Content-Type    <--->      @Consumes

服务器会根据客户端请求的Content-TypeAccept来处理数据。客户端发送请求时会在headers中声明它发送的数据格式Content-Type,同时也会声明希望接收的响应格式Accept

例如:客户端发送以下headers:

  • Content-Type=text/xml(它发送了一个XML)
  • Accept=application/json(它期望得到一个JSON作为响应)

服务器需要为相应的方法加上下列注解(如果类级别有这些注解并且没有明确声明该方法则使用类级别的注解):

  • @Consumes(MediaType.TEXT_XML)(从客户端获取XML)
  • @Produces(MediaType.APPLICATION_JSON)(向客户端发送JSON)

注意:

  1. 服务器可以配置成能够接收/发送多种格式的数据。例如: 如果方法声明如下注解:@Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }),那么一个客户端发送JSON,另一个发送XML都可以调用同一个方法。

  2. MediaType只是一个String常量。

public final static String APPLICATION_JSON = "application/json";
public final static String TEXT_XML = "text/xml";

2
您可以使用ContainerResponseFilter,在输入请求中未提供默认的Accept头时设置它。
@Provider
public class EntityResponseFilter implements ContainerResponseFilter {

    private MediaType getExternalMediaType(){
        MediaType mediaType = new MediaType("application", "vnd.xxx.resource+json")
        return mediaType; 
    }

    @Override
    public void filter( ContainerRequestContext reqc , ContainerResponseContext resc ) throws IOException {
        MediaType mediaType = getExternalMediaType(); 
        List<MediaType> mediaTypes = reqc.getAcceptableMediaTypes();
        if( mediaTypes.contains(mediaType) ) {   
            resc.setEntity( resc.getEntity(), new Annotation[0], mediaType );
        }
        // ...
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接