2017-12-17 2 views
0

제 3자가 제공 한 이전 웹 서비스를 호출합니다. 나는 봄 RestTemplate 사용하고 있습니다 : 내가 XML을받을Spring RestTemplate에서 "<! DOCTYPE ... dtd>"가 포함 된 XML을 비동기로 변환 할 수 없습니다.

HttpEntity<MyRequest> requestHttpEntity = new HttpEntity<>(requestBody, headers); 
MyResponse response = restTemplate.postForEntity(url, requestHttpEntity, MyResponse.class); 

을 응답으로 (내가 영향을 미칠 수없는 형식, 그것은 제 3 자 서비스의) :

<?xml version="1.0" encoding="ISO-8859-1"?> 
<!DOCTYPE MyResponse SYSTEM "http://example.com:8080/some/path/MyResponse.dtd"> 

<MyResponse> 
    ... 
</MyResponse> 

postForEntity() 방법은 예외를 throw는

org.springframework.web.client.RestClientException: 
    Error while extracting response for type [class com.example.MyResponse] and content type [text/xml;charset=ISO-8859-1]; 
nested exception is org.springframework.http.converter.HttpMessageNotReadableException: 
    Could not unmarshal to [class com.example.MyResponse]: null; 
nested exception is javax.xml.bind.UnmarshalException 

- with linked exception: 
    [org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; 
    DOCTYPE is disallowed when the feature 
    "http://apache.org/xml/features/disallow-doctype-decl" set to true.] 

여기서 http://apache.org/xml/features/disallow-doctype-decl 기능에 대한 유일한 참고 자료를 찾았습니다. https://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl

질문 : Spring RestTemplate의 자동화 된 동작을 완전히 피하지 않고 어떻게 마샬링을 사용자 정의 할 수 있습니까? 나는 unmarshaler가 DTD 참조가있는 XML 포함 요소를 받아들이도록 강요하고자합니다.

이 질문은 내 다른 질문 How to customize automatic marshaling in Spring RestTemplate to produce/modify XML headers (encoding, DOCTYPE)과 관련이 있지만, 제안 된 해결책은 여기에서 쉽게 적용 할 수 없습니다.

+1

이 속성을 false로 설정하기 만하면됩니다. 'HttpMessageConverter'을 설정하여 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/converter/을 구성 할 수 있습니다. xml/Jaxb2RootElementHttpMessageConverter.html # setSupportDtd-boolean-. 기본적으로이 속성은 DTD 지원을 사용하지 않도록 설정하는 'false'로 설정됩니다. 이는 DTD 지원을 활성화 할 때 보안 관련 사항과 관련이 있습니다. –

+0

@ M.Deinum 그것은 마술처럼 작동합니다 (당신이 * true * :)에 속성을 설정한다고 가정), 감사합니다! 전에 방법을 알아 채지 못했습니다. 제발 대답 해주세요, 받아들이 길예요! 그리고 내 비슷한 질문에 대한 간단한 답이 있습니까? https://stackoverflow.com/q/47836310/2886891? Alex Savitsky의 대답 *이 효과가 있지만, 해킹처럼 보입니다. –

+0

여기에 대한 답변을 참조하십시오. 특히 다른 질문에 대답해야하는 두 번째 부분을 참조하십시오. –

답변

1

기본적으로 Jaxb2RootElementHttpMessageConverter은 DTD 지원 (및 해당 XML 엔터티 지원)을 비활성화합니다. 그 이유는 보안에 영향이 있기 때문입니다 (SPR-11376 참조).

Jaxb2RootElementHttpMessageConverter에서 활성화하려면 supportDtd 속성을 true으로 설정하여 다시 사용하도록 설정합니다. 그러나 이것이 잠재적 인 보안 문제를 열어 줄 것이라는 점을 알고 있어야합니다.

@Bean 
public Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter() { 
    Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter(); 
    converter.setSupportDtd(true); 
    return converter; 
} 

추가 구성을 추가 할 필요없이 지원을 다시 구성하기에 충분해야합니다. 한가지 기억해야 할 점은이 컨트롤러가 전 세계적으로 사용 가능한 Jaxb2RootElementHttpMessageConverter을 구성하므로 모든 컨트롤러에 영향을 미치고 사용하고자하는 경우 일 수 있습니다.

RestTemplate의 인스턴스를 만들 때 사용해야하는 RestTemplateBuilder을 사용하는 대신 특정 RestTemplate에만 영향을 줄 수 있습니다.

@Bean 
public RestTemplate yourRestTemplate(RestTemplateBuilder builder) { 
    Jaxb2RootElementHttpMessageConverter converter = new Jaxb2RootElementHttpMessageConverter(); 
    converter.setSupportDtd(true); 

    return builder.messageConverters(converter).build() 
} 

이 방법 당신은 RestTemplate의 해당 인스턴스가 특정 구성하고 당신이 좋아하는 무엇을 구성 할 수 있습니다.

+0

나쁘다 ...'additionalConverters' 대신'messageConverters'를 사용하십시오. –

+0

둘 다 잘못되었으므로 (적어도 Spring Boot 1.5.x에서는)'messageConverters'를 사용해야합니다. 이렇게하면 기존의 모든 메시지 변환기가 대체되고 다른 변환기는 기본 변환기 목록에 추가됩니다.수정 된 응답을 사용하면 단일 메시지 변환기로 'RestTemplate'을 얻을 수 있습니다. –

+0

그러면 스프링 부트의 다른 부분이 빠져 있어야합니다. 기본적으로 다른 것들도 추가됩니다. 저장하고 싶다면'additional * '대신'messageConverters'를 사용하십시오. –

관련 문제