Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
仅当ContentType==JSON时才更改Java筛选器中的ContentType或CharacterEncoding_Java_Filter_Content Type_Jersey 2.0 - Fatal编程技术网

仅当ContentType==JSON时才更改Java筛选器中的ContentType或CharacterEncoding

仅当ContentType==JSON时才更改Java筛选器中的ContentType或CharacterEncoding,java,filter,content-type,jersey-2.0,Java,Filter,Content Type,Jersey 2.0,我试图确保来自基于Jersey的java应用程序的所有JSON响应都有一个UTF-8字符编码参数附加到其ContentType头中 因此,如果是JSON响应,我希望内容类型的响应头是 内容类型:application/json;字符集=UTF-8 EDIT:我知道我可以根据具体情况进行编辑,但我希望在全局范围内进行编辑,因此它会影响所有内容类型为“application/json”的内容响应。 如果我只是尝试在我的过滤器中设置字符编码,而不考虑内容类型,它就可以正常工作。但我只想在Conten

我试图确保来自基于Jersey的java应用程序的所有JSON响应都有一个UTF-8字符编码参数附加到其ContentType头中

因此,如果是JSON响应,我希望
内容类型的响应头是

内容类型:application/json;字符集=UTF-8

EDIT:我知道我可以根据具体情况进行编辑,但我希望在全局范围内进行编辑,因此它会影响所有内容类型为“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()
    {
    }
}

我见过其他人,但他们似乎都没有这个问题。我已尝试将我的筛选器注册为第一个筛选器和最后一个筛选器,但没有成功。

不100%确定我是否达到了您的目标。 是否要在调用后设置标头字符集

chain.doFilter(request, response)
?

如果是这种情况,恐怕你不能,因为很可能在那一点上,在chain.doFilter(request,response)返回并处理请求之后,内容字符集已发送到客户端,因此您不能再对其进行更改。

作为参考,您的问题的解决方案是重新编码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();
    }
}

这样做是行不通的

调用
chain.doFilter(请求、响应)时标题已刷新,以后无法重置

你能做的其实是一个快速而肮脏的把戏:

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”)
,多亏了本页上的其他答案,我找到了一种方法。。。。非常接近他们的建议,但事实证明,我能让它工作的唯一方法是重写“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
    }
}

使用
ClientFilter
也可以做到这一点,我刚刚遇到一个StackOverflow帖子,其目的类似:


成功使用了
ContainerResponseFilter

公共类ContentTypeEncodingFilter实现ContainerResponseFilter{
@凌驾
公共无效筛选器(ContainerRequestContext requestContext、ContainerResponseContext responseContext responseContext)引发IOException{
String contentType=responseContext.getHeaderString(HttpHeaders.CONTENT\u类型);
if(contentType==null){
返回;
}
ContentType parsedType=ContentType.parse(ContentType);
if(parsedType.getCharset()!=null){
返回;
}
ContentType encodedType=parsedType.withCharset(StandardCharsets.UTF_8);
responseContext.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE,encodedType.toString());
}
}

嘿。。。谢谢我试图确保所有ContentType为“application/json”的响应也使用字符集头“UTF-*”…我能想到的最简单的方法是将所有json操作分组到一个公共路径前缀中,然后在过滤器中根据请求路径设置内容类型。例如,如果主机名为foo.com,则所有json操作都具有以下url前缀*。现在,在过滤器中,在调用chain.doFilter之前,如果url前缀为*hey,请设置内容类型!谢谢你的主意。。。。它似乎工作正常,并被其他响应所覆盖(如内容类型:image/jpeg)。。。。荣誉请注意,我必须确保这是链中的第一个过滤器,以使其正常工作,正如预期的那样。。。。我以为它起作用了,但我似乎不能再让它起作用了。。。。在悬赏结束之前,我有点急于尝试解决方案,所以也许我看到了一些不存在的东西。。。。我注意到在上面的代码中,它说
ct.toUpperCase().startsWith("application/json
,这永远不会是真的…所以我猜这根本不会起作用…谢谢你的建议…如果我发现任何不同的地方,我会向你汇报…你说你只是想添加字符集。如果你在做其他事情,你可以用同样的方式捕捉它。你怎么知道响应是否是你的JS打开还是不打开?通过URL?我想这可能是问题的一部分。我知道的唯一方法是查看ContentType标题,它似乎只有一些内容(即非空)调用chain.doFilter后。我不想在所有响应中将字符集设置为UTF-8,因为这会导致我所读的IE8图像出现问题。如果内容类型为“text/html”,我想在响应标题中将缓存控制设置为“no Cache,no store,must revlidate,max age=0”我被这个案子堵住了。你能帮个忙吗?嗯……似乎同样的想法对我来说应该是可行的。在谷歌上搜索一下,两者都可以回答你的问题