【问题标题】:Gzip compression with MockRestServiceServer使用 MockRestServiceServer 进行 Gzip 压缩
【发布时间】:2016-06-09 09:50:29
【问题描述】:

我有一个基于 Spring 3.2.0 构建的 Java 应用程序,它执行对提供 JSON 数据的 REST api 的外部调用。

调用由 Spring RestTemplate 类执行,Jackson 2.2.3 作为序列化器/反序列化器。

调用是函数式的,支持普通响应和压缩响应。

为了测试 Junit 调用,我使用 MockRestServiceServer。一切正常,直到我尝试引入 gzip 压缩。我无法在官方文档中找到如何在 MockRestServiceServer 中激活 gzip 压缩,所以我选择了手动路线:

  • 手动压缩响应的字符串内容

  • 在标头中将“Content-Encoding”设置为“gzip”

不幸的是,杰克逊在反序列化响应正文时一次又一次地收到相同的错误:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Illegal character ((CTRL-CHAR, code 31)): 
only regular white space (\r, \n, \t) is allowed between tokens
at [Source: java.io.ByteArrayInputStream@110d68a; line: 1, column: 2];
nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): 
only regular white space (\r, \n, \t) is allowed between tokens

这是当前代码(由于公司数据而重做...)

测试类

public class ImportRefCliCSTest {

    @Autowired
    private MyService myService;

    private MockRestServiceServer mockServer;

    @Before
    public void before() {
        mockServer = MockRestServiceServer.createServer(myService.getRestTemplate());
    }

    @Test
    public void testExternalCall() throws IOException {

        String jsonData = "[{\"testing\":\"Hurray!\"}]";
        HttpHeaders headers = new HttpHeaders();
        headers.add( "Content-Encoding", "gzip" );

        DefaultResponseCreator drc = withSuccess( gzip( jsonData ),
            MediaType.APPLICATION_JSON ).headers( headers );

        mockServer.expect( requestTo( myService.EXTERNAL_CALL_URL ) )
            .andExpect( method( HttpMethod.GET ) ).andRespond(drc);

        myService.performCall();
    }


    private static String gzip(String str) throws IOException {
        if (str == null || str.length() == 0) {
            return str;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(out);
        gzip.write(str.getBytes());
        gzip.close();
        String outStr = out.toString();
        return outStr;
    }
}

服务类

@Service
public class MyService {

    public static final String EXTERNAL_CALL_URL = "<myURL>";
    private RestTemplate restTemplate;

    {
        restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(
            HttpClientBuilder.create().build()));
    }


    public void performCall() {

        try {
            HttpHeaders requestHeaders = new HttpHeaders();
            requestHeaders.add("Accept-Encoding", "gzip");
            HttpEntity<MyObject[]> requestEntity = new HttpEntity<MyObject[]>(requestHeaders);

            ResponseEntity<MyObject[]> responseEntity = restTemplate.exchange(
                EXTERNAL_CALL_URL, HttpMethod.GET, requestEntity, MyObject[].class);
            MyObject[] array = responseEntity.getBody();
            if (array == null || array.length == 0) {
                return null;
            }
            return null;
        } catch (RestClientException e) {
            return null;
        }
    }

    public RestTemplate getRestTemplate(){
        return restTemplate;
    }
}

我觉得我错过了什么。手动 gzip 压缩似乎相当可疑。

有人对此有想法吗?

提前感谢您的回答!

【问题讨论】:

    标签: java junit compression gzip resttemplate


    【解决方案1】:

    当程序将 gzip 内容转换为字符串时,一些字节被折叠。所以客户端无法解压并抛出异常。一个解决方案是返回byte[]:

    private static byte[] gzip(String str) throws IOException {
        if (str == null || str.length() == 0) {
            return new byte[0];
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(out);
        gzip.write(str.getBytes());//consider to use str.getBytes("UTF-8")
        gzip.close();
        return out.toByteArray();
    }
    

    【讨论】:

    • 嗨@beckyang。谢谢您的回答。我会试试这个,然后回来找你
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多