html2canvas에서 지도의 캡처를 찍으려고 했는데, 이상하게 카카오지도 부분만 나오지 않았다.
알아보니, html2canvas에서 외부이미지는 CORS정책 때문에 캡쳐가 안된다고 한다. 내 쪽 서버의 origin과 이미지 요청에 대한 응답 서버의 origin이 맞지 않아서 브라우저에서 막기 때문이다.
CORS에 대한 내용은 아래에서 확인하자.
https://wouldyou.tistory.com/37
이를 해결하기 위해서는 proxy를 사용해 우회해야 하는데, 이 옵션을 html2canvas에서 지원한다.
들어가보면 아주 친절하게도 node.js버전은 라이브러리가 잘 되어있는데 java버전 라이브러리는 없다^^
php버전도 있다고한다 https://github.com/brcontainer/html2canvas-php-proxy
필자는 java를 사용하므로 node.js버전의 html2canvas-proxy라이브러리를 참고하여 controller에서 직접 구현했다.
java로 html2canvas proxy 만들기
아래처럼 proxy옵션을 주면 html2canvas에서 내 origin + proxy뒤에 이미지를 요청하는 url과 responseType이 쿼리로 붙어 요청을 한다.
html2canvas(document.body, {proxy : '/html2canvas-proxy'}).then(function(canvas) {
document.body.appendChild(canvas);
});
당연히, 이 요청을 받을 수 있는 controller가 없어서 404 오류가 난 것을 볼 수 있다.
그렇다면 이 GET요청을 받는 Html2canvasProxyController.java를 만들고 쿼리의 url부분만 따로 떼어내어 재요청한 후 응답받은 이미지를 return해주면 되지 않을까?
된다. 실제로 node.js버전의 html2canvas-proxy라이브러리를 보면 같은 방식으로 처리했다.
node.js 버전의 html2canvas-proxy는 어떻게 처리했을까?
proxy옵션을 주면 아래와 같이 url과 responseType이 쿼리로 붙는다고 이야기했다.
http://localhost:8080/html2canvas-proxy?url=???&responseType=blob
html2canvas-proxy 코드를 보면, responseType에는 blob과 text가 있는 듯 하다.
https://github.com/niklasvh/html2canvas-proxy-nodejs/blob/master/server.js
(코드를 보면 알 수 있다.)
blob인 경우에는 먼저 url로 새로 요청을 하여 응답을 받는다.
그리고 받은 응답을 그대로 내려준다. ( java에서는 byte[]로 내려준다.)
req.pipe(request(req.query.url).on('error', next)).pipe(res);
text인 경우에는 url로 새로 요청을 하여 받은 응답을 아래와 같은 String으로 내려준다.
res.send(
`data:${response.headers['content-type']};base64,${Buffer.from(
body,
'binary'
).toString('base64')}`
);
이 방식을 카피하여 java버전을 만들어보자.
사실 필자는 map만 잘 보여지면 되어서 reponseType=text는 처리하지 않았다. 이 부분은 여러분이 만들어서 꼭 공유해주시면 좋겠다 ㅎㅎㅎ
Controller에서 proxy처리하기
먼저 javascript코드는 proxy옵션을 주어 만들어둔다.
html2canvas(kakaoDiv, {proxy: NS.ctx+'/html2canvas/proxy.json', allowTaint:false})
.then(canvas => {
const a = document.createElement('a');
a.href = canvas.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
a.download = 'map.png';
a.click();
});
이제 proxy옵션의 GET요청을 받는 Html2canvasProxyController.java를 만들자.
blob인 경우만 처리했다.
1. req에서 url부분을 따로 떼어내어, 새로 GET요청을 보낸다.
2. 받응 응답을 byte로 변환하여 반환한다.
@Controller
@RequestMapping(value="/html2canvas")
public class Html2CanvasProxy {
@RequestMapping(value="/proxy.json", method=RequestMethod.GET)
@ResponseBody
public byte[] html2canvasProxy(HttpServletRequest req) {
byte[] data = null;
try {
URL url = new URL(URLDecoder.decode(req.getParameter("url"),
java.nio.charset.StandardCharsets.UTF_8.toString()));
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setRequestMethod("GET");
if(connection.getResponseCode() == 200) {
data = IOUtils.toByteArray(connection.getInputStream());
} else {
System.out.println("responseCode : "
+ connection.getResponseCode());
}
} catch (MalformedURLException e) {
data = "wrong URL".getBytes(java.nio.charset.StandardCharsets.UTF_8);
} catch(Exception e) {
System.out.println(e);
}
return data;
}
}
이제 지도를 잘 다운받는 것을 볼 수 있다!
해당 코드는 아래 github에서 다운받을 수 있다
https://github.com/yjs000/captureHTML
'Spring' 카테고리의 다른 글
[SpringBoot] spring boot 웹프로젝트 dependency 간단히 살펴보기 (0) | 2022.03.08 |
---|---|
[SpringBoot] SpringBoot에서 thymeleaf 사용하기 (0) | 2022.03.07 |
[SpringBoot] SpringBoot에서 npm사용하기 (0) | 2022.03.07 |
[SpringBoot] IntelliJ Community에서 Spring Boot 프로젝트 만들기 (0) | 2022.03.07 |
[spring] 404오류가 나는 경우, mapper쪽 오류 해결 (0) | 2021.11.09 |