복붙노트

[SPRING] Spring-Web의 RestTemplate에서 gzip으로 인코딩 된 응답을 구문 분석하는 방법

SPRING

Spring-Web의 RestTemplate에서 gzip으로 인코딩 된 응답을 구문 분석하는 방법

내가 RESTful 웹 서비스를 사용하여 api.stackexchange.com에서 id로 사용자를 호출하는 예제를 수정 한 후에 JsonParseException을 얻는다.

com.fasterxml.jackson.core.JsonParseException : 잘못된 문자 ((CTRL-CHAR, 코드 31)) : 토큰 사이에 공백 (\ r, \ n, \ t) 만 허용됩니다.

api.stackexchange.com의 응답이 gzip으로 압축됩니다.

gzip 압축 응답을 Spring-Web RestTemplate에 추가하는 방법은 무엇입니까?

나는 스프링 부트 부모 버전을 사용하고있다. 1.3.1.RELEASE 그러므로 Spring-Web 4.2.4-RELEASE

여기 내 조정 된 예가 있습니다 :

User.java

package stackexchange.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonNaming(LowerCaseWithUnderscoresStrategy.class)
public class User {

    // Properties made public in order to shorten the example
    public int userId;
    public String displayName;
    public int reputation;

    @Override
    public String toString() {
        return "user{"
                + "display_name='" + displayName + '\''
                + "reputation='" + reputation + '\''
                + "user_id='" + userId + '\''
                + '}';
    }
}

CommonWrapper.java

package stackexchange.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonNaming(LowerCaseWithUnderscoresStrategy.class)
public class CommonWrapper {

    // Properties made public in order to shorten the example
    public boolean hasMore;
    // an array of the type found in type
    public User[] items;
    public int page;
    public int pageSize;
    public int quotaMax;
    public int quotaRemaining;

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (User user : items) {
            sb.append("{" + user.toString() + "}\n");
        }

        return "common_wrapper{"
        + "\"items\"=[\n"
        + sb
        + "]"
        + "has_more='" + hasMore + '\''
        + "page='" + page + '\''
        + "page_size='" + pageSize + '\''
        + "quota_max='" + quotaMax + '\''
        + "quota_remaining='" + quotaRemaining + '\''
        + '}';
    }
}

StackExchange.java

package stackexchange;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.web.client.RestTemplate;

import stackexchange.dto.CommonWrapper;

import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(LowerCaseWithUnderscoresStrategy.class)
public class StackExchange implements CommandLineRunner{

    private static final Logger log = LoggerFactory.getLogger(StackExchange.class);

    public static void main(String args[]) {
        SpringApplication.run(StackExchange.class);
    }

    @Override
    public void run(String... strings) throws Exception {

        RestTemplate restTemplate = new RestTemplate();
        CommonWrapper response = restTemplate
                .getForObject(
                        "https://api.stackexchange.com/2.2/users/4607349?site=stackoverflow",
                        CommonWrapper.class);

        log.info(response.toString());
    }

}

pom.xml - 예제와 동일

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>stackexchangetest</groupId>
  <artifactId>stackexchangetest</artifactId>
  <version>0.0.1</version>
  <name>stackexchangetest</name>
  <description>api.stackexchange.com Test</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.1.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>   
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

해결법

  1. ==============================

    1.기본 requestFactory를 Apache HttpClient로 바꾸기 :

    기본 requestFactory를 Apache HttpClient로 바꾸기 :

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

    pom.xml에 Apache HTTP 클라이언트 추가

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <!--Version is not needed when used with Spring Boot parent pom file -->
        <version>4.5.1</version>
    </dependency>
    
  2. ==============================

    2.

    private String callViaRest(String requestString, Steps step) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_XML);
        headers.add("Accept-Encoding", "application/gzip");
        HttpEntity<String> entity = new HttpEntity<String>(requestString, headers);
    
        byte[] responseBytes = jsonRestTemplate
                .exchange("yourUrl", HttpMethod.POST, entity, byte[].class).getBody();
        String decompressed = null;
        try {
            decompressed= new String(CompressionUtil.decompressGzipByteArray(responseBytes),Charsets.UTF_8);
        } catch (IOException e) {
            LOGGER.error("network call failed.", e);
        }
        return decompressed;
    }
    
  3. from https://stackoverflow.com/questions/34415144/how-to-parse-gzip-encoded-response-with-resttemplate-from-spring-web by cc-by-sa and MIT license