Jersey / Rest 默认字符编码

Posted

技术标签:

【中文标题】Jersey / Rest 默认字符编码【英文标题】:Jersey / Rest default character encoding 【发布时间】:2011-07-27 17:04:12 【问题描述】:

返回 JSON 时,泽西似乎失败了... 这个:

@GET
@Produces( MediaType.APPLICATION_JSON + ";charset=UTF-8")
public List<MyObject> getMyObjects() 
    return ....;

需要返回 JSON utf-8 编码。如果我只使用

@Produces( MediaType.APPLICATION_JSON)

失败,例如德语变音符号 (üöä),将以错误的方式返回。

两个问题: 1 - 对于 JSON utf-8 ist 标准 - 为什么不使用 Jersey? 2 - 如果收到 JSON 请求,我可以为整个 REST-Servlet 设置 utf-8 吗? 我在 android 上使用 Jersey 1.5 和 Crest 1.0.1...

【问题讨论】:

它们是如何返回的?你能展示一些示例输出吗? 它返回 Löwe 而不是 Löwe(英文中的 Lion),但正如我所说,如果我使用 @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8") 它可以工作......跨度> 真的只有我一个人有这个问题吗? 那么您自己的问题已经解决了吗?只需将字符集添加到末尾即可。显示数据的似乎是客户端,而不是泽西岛。 是的,这对我来说是解决方案,但对我来说有点奇怪。这真的是解决这个问题的唯一方法吗? 【参考方案1】:

SRG 的建议就像一个魅力。然而,由于 Jersey 2.0 的接口略有不同,所以我们不得不稍微调整一下过滤器:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

import javax.ws.rs.core.MediaType;

public class CharsetResponseFilter implements ContainerResponseFilter 
    @Override
    public void filter(ContainerRequestContext request, ContainerResponseContext response) 
        MediaType type = response.getMediaType();
        if (type != null) 
            String contentType = type.toString();
            if (!contentType.contains("charset")) 
                contentType = contentType + ";charset=utf-8";
                response.getHeaders().putSingle("Content-Type", contentType);
            
        
    

【讨论】:

感谢您的更新!我刚开始使用泽西岛并偶然发现了这个问题,您的解决方案完美无缺! Grizzly 用户注意:要注册此过滤器,您只需在启动方法中调用 rc.register(com.example.CharsetResponseFilter.class);(我使用的是教程中生成的样板代码)。【参考方案2】:

我遇到了同样的问题:我不喜欢到处都在“@Produces”标签中添加字符集。

我在这里找到了解决方案:http://stephen.genoprime.com/2011/05/29/jersey-charset-in-content-type.html

基本上,您只需添加一个将添加字符集的响应过滤器(例如,如果当前返回的内容类型是文本、xml 或 json)

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

import javax.ws.rs.core.MediaType;

public class CharsetResponseFilter implements ContainerResponseFilter 

    public ContainerResponse filter(ContainerRequest request, ContainerResponse response) 

        MediaType contentType = response.getMediaType();
        response.getHttpHeaders().putSingle("Content-Type", contentType.toString() + ";charset=UTF-8");

        return response;
    

并注册过滤器:

ServletAdapter jerseyAdapter = new ServletAdapter();
jerseyAdapter.addInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.my.package.MyResponseFilter"); 

当然,Guice 也可以使用,例如在你的类中扩展 ServletModule :

final Map<String, String> parameters = new HashMap<String, String>();
parameters.put("com.sun.jersey.spi.container.ContainerResponseFilters", com.package.JerseyCharsetResponseFilter.class.getName());
serve("/*").with(GuiceContainer.class, parameters);

【讨论】:

他们如何实现这个can be found here的完整、更详细的来源,并允许方法已经设置“Content-Type”的情况,从而允许在需要的地方进行覆盖。跨度> 【参考方案3】:

SRGs 和 martins 解决方案对我来说效果很好。

但是,我必须对过滤器应用以下更改:

如果客户端发出带有 Accept 标头的请求,Jersey 会在内容类型中添加一个质量因子。如下所示:

没问题:没有 Accept 头的请求:

curl -i http://www.example.com/my-rest-endpoint

response.getMediaType().toString()application/json。我们可以简单地追加;charset=utf-8

问题:带有 Accept 标头的请求:

curl -i -H "Accept: application/json" http://www.example.com/my-rest-endpoint

response.getMediaType().toString()application/json, q=1000。我们不能简单地追加;charset=utf-8,因为这会导致以下异常:

java.lang.IllegalArgumentException: Error parsing media type 'application/json, q=1000;charset=utf-8'
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:92) ~[na:na]
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:60) ~[na:na]
    at javax.ws.rs.core.MediaType.valueOf(MediaType.java:179) ~[na:na]
    ...
Caused by: java.text.ParseException: Next event is not a Token
    at org.glassfish.jersey.message.internal.HttpHeaderReader.nextToken(HttpHeaderReader.java:129) ~[na:na]
    at org.glassfish.jersey.message.internal.MediaTypeProvider.valueOf(MediaTypeProvider.java:110) ~[na:na]
    at org.glassfish.jersey.message.internal.MediaTypeProvider.fromString(MediaTypeProvider.java:90) ~[na:na]
    ... 193 common frames omitted

我建议使用以下代码来解决此问题:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MediaType;

public class CharsetResponseFilter implements ContainerResponseFilter 

    @Override
    public void filter(ContainerRequestContext request, ContainerResponseContext response) 
        MediaType type = response.getMediaType();
        if (type != null) 
            if (!type.getParameters().containsKey(MediaType.CHARSET_PARAMETER)) 
                MediaType typeWithCharset = type.withCharset("utf-8");
                response.getHeaders().putSingle("Content-Type", typeWithCharset);
            
        
    

【讨论】:

以上是关于Jersey / Rest 默认字符编码的主要内容,如果未能解决你的问题,请参考以下文章

Jersey - servlet 上下文路径和/或 servlet 路径包含百分比编码的字符

django rest_framework中将json输出字符强制为utf-8编码

在鼓励使用特殊字符的密码等字段的 REST API 中,避免 WAF 误报的最佳编码实践是啥

Django REST Framework Serializer和JSONRenderer编码

python字符串编码

Spring Boot 2.5.0 - REST 控制器,MockMvc 不是 UTF-8