我试图确保来自基于Jersey的java应用程序的所有JSON响应都在其ContentType标头中附加了UTF-8字符编码参数。
因此,如果它是JSON响应,我希望Content-Type
的响应标头为
Content-Type:application / json; charset = 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是" application / json"。我发现response.getContentType()方法总是返回null,除非我先调用chain.doFilter。但是如果我在此之后尝试更改字符编码,它似乎总是会被覆盖。
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,但他们似乎都没有这个问题。我已经尝试将我的过滤器注册为第一个,最后一个过滤器没有运气。
答案 0 :(得分:7)
感谢此页面上的其他答案,我找到了一种方法来做到这一点......非常接近他们的建议,但事实证明我能让它工作的唯一方法是覆盖&#34 ;的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
}
}
答案 1 :(得分: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")
。
答案 2 :(得分: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();
}
}
答案 3 :(得分:1)
使用ClientFilter
也可以这样做,我刚刚遇到类似目的的StackOverflow帖子:
答案 4 :(得分: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());
}
}
答案 5 :(得分:0)
不是100%肯定我得到了你想要达到的目标。 是否要在调用
后设置标题字符集chain.doFilter(request, response)
如果是这种情况我害怕你不能,因为那时很可能,在那个chain.doFilter(请求,响应)已经返回并且处理了请求之后,内容字符集已经被发送到客户端了,因此你不能再改变它了。