更改内容类型或字符编码在Java中仅筛选如果内容类型=== JSON

问题描述 投票:5回答:6

我想,以确保从位于新泽西州的Java应用程序的所有JSON响应有附加到他们的ContentType标头一个UTF-8字符编码参数。

所以,如果它是一个JSON响应,我想响应头为Content-Type

内容类型:应用/ JSON;字符集= UTF-8

EDIT: I know I can do this on a case by case basis, but I'd like to do it globally, so it affects all content responses that have a content type of "application/json".

如果我只是尝试,并设置在我的过滤器中的字符编码,无论内容类型,它工作正常。但我只是想设置的字符编码如果将contentType是“应用/ JSON”。我觉得除非我先打电话chain.doFilter的response.getContentType()方法总是返回null。但是,如果我尝试在此之后改变字符编码,它似乎总是会被覆盖。

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.ws.rs.core.MediaType;

public class EnsureJsonResponseIsUtf8Filter implements Filter
{
    private class SimpleWrapper extends HttpServletResponseWrapper
    {
        public SimpleWrapper(HttpServletResponse response)
        {
            super(response);
        }

        @Override
        public String getCharacterEncoding()
        {
            return "UTF-8";
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    {
        chain.doFilter(request, response);

        if (response.getContentType() != null && response.getContentType().contains(MediaType.APPLICATION_JSON))
        {
            response.setCharacterEncoding("UTF-8");
            chain.doFilter(request, new SimpleWrapper((HttpServletResponse) response));
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
    }

    @Override
    public void destroy()
    {
    }
}

我见过的其他similar questions,但没有人似乎有这个问题。我试着注册我的过滤器,没有运气第一,和最后一个过滤器。

java filter content-type jersey-2.0
6个回答
7
投票

由于此页面上的其他答案,我发现了一个办法做到这一点....非常接近他们被暗示,但事实证明,我能得到它的工作的唯一办法就是越权“的getOutputStream”看看将contentType在这一点上。我已经把这个过滤器链中的第一个过滤器,它似乎很好地工作。

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.ws.rs.core.MediaType;

public class EnsureJsonIsUtf8ResponseFilter implements Filter
{
    final String APPLICATION_JSON_WITH_UTF8_CHARSET = MediaType.APPLICATION_JSON + ";charset=" + java.nio.charset.StandardCharsets.UTF_8;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
    {
        HttpServletResponse r = (HttpServletResponse) response;
        HttpServletResponse wrappedResponse = new HttpServletResponseWrapper(r) 
        {
            @Override
            public ServletOutputStream getOutputStream() throws java.io.IOException
            {
                ServletResponse response = this.getResponse();

                String ct = (response != null) ? response.getContentType() : null;
                if (ct != null && ct.toLowerCase().startsWith(MediaType.APPLICATION_JSON))
                {
                    response.setContentType(APPLICATION_JSON_WITH_UTF8_CHARSET);
                }

                return super.getOutputStream();
            }
        };

        chain.doFilter(request, wrappedResponse); 
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        // This method intentionally left blank
    }

    @Override
    public void destroy()
    {
        // This method intentionally left blank
    }
}

4
投票

这不会以这种方式工作。

当你调用chain.doFilter(request, response);你的头已经被刷新,你不能重新设置以后。

你可以做的其实是一个快速和肮脏的伎俩:

public void doFilter(...) {
    HttpServletResponse resp = new HttpServletResponseWrapper(response) {
    public void setContentType(String ct) {
        if(ct!=null && ct.toLowerCase().startsWith("application/json")) {
            super.setContentType("application/json;charset=UTF-8");
        } else {
            super.setContentType(ct);
        }
   }
}

// Set content type manually to override any potential defaults,
// See if you need it at all
response.setContentType("application/json;charset=UTF-8");

chain.doFilter(request, resp); // Inject our response!
}

编辑:ct.toUpperCase().startsWith("application/json")改为ct.toLowerCase().startsWith("application/json")


1
投票

使用this answer作为参考解决您的问题,以如下所示的JSON文本进行重新编码:

public void doFilter(...) {
    final CharResponseWrapper wrappedResponse =
            new CharResponseWrapper((HttpServletResponse) response);

    chain.doFilter(request, wrappedResponse);

    final String content = wrappedResponse.toString();

    final String type = wrappedResponse.getContentType();
    if (type != null && type.contains(MediaType.APPLICATION_JSON)) {
        // Re-encode the JSON response as UTF-8.
        response.setCharacterEncoding("UTF-8");
        final OutputStream out = response.getOutputStream();
        out.write(content.getBytes("UTF-8"));
        out.close();
    }
    else {
        // Otherwise just write it as-is.
        final PrintWriter out = response.getWriter();
        out.write(content);
        out.close();
    }
}

1
投票

这也可以使用ClientFilter,我刚刚碰到的StackOverflow职位相似的目的是可行的:

https://stackoverflow.com/a/7464585/26510


1
投票

有使用ContainerResponseFilter成功:

public class ContentTypeEncodingFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        String contentType = responseContext.getHeaderString(HttpHeaders.CONTENT_TYPE);
        if (contentType == null) {
            return;
        }
        ContentType parsedType = ContentType.parse(contentType);
        if (parsedType.getCharset() != null) {
            return;
        }
        ContentType encodedType = parsedType.withCharset(StandardCharsets.UTF_8);
        responseContext.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, encodedType.toString());
    }
}

0
投票

不是100%肯定我得到了你想要达到的目标。你想调用后设置页眉字符集

chain.doFilter(request, response)

?

如果这是我怕的情况下,你不能因为很可能在这一点上,那chain.doFilter(请求,响应)已经返回处理请求后,内容的字符集已经被发送到客户端,因此,你不能改变它了。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.