* RN에서 크롤링 기능을 구현하면서, 다양한 경우의 오류 해결 과정을 함께 기록함
* euc-kr to utf-8 방법은 맨 아래로 바로 이동
#1. fetch() 를 통해 호출 시, 'https' 프로토콜 및 'utf-8'로 인코딩된 웹페이지는 ios/android 모두 정상적으로 데이터를 잘 읽어왔다.
1) fetch() 를 통해 url 호출 시 응답 값
...
const Crawling = async () => {
const res = await fetch(`https://bocoder.tistory.com/`);
console.log(res);
}
...
2) fetch().text 를 통해 url 호출 시 응답 값
...
const Crawling = async () => {
const res = await fetch(`https://bocoder.tistory.com/`);
const resString = await res.text();
console.log(resString);
}
...
#2. 'http' 프로토콜로 되어있는 url 호출 시, ios 에서만 'TypeError: Network request failed' 오류 발생
- 원인 : iOS 9 버전 이후부터 적용된 보안 정책으로, 보안에 취약한 네트워크를 차단시킬 목적이라고 한다.
- 해결 : https://bocoder.tistory.com/101?category=904878
#3. 'euc-kr'로 인코딩된 url 호출 시, ios 는 호출 자체가 안되고 android는 한글이 깨져서 euc-kr to utf-8 디코딩이 필요함
...
const Crawling = async () => {
const res = await fetch(`http://www.ktfs.or.kr/bbs/board.php?bo_table=schedule/`);
const resString = await res.text();
console.log(resString);
}
...
1) iconv-lit 라이브러리를 이용해서, euc-kr 로 받아온 웹데이터를 utf-8로 변환해 보았다.
import iconv from 'iconv-lite';
...
const Crawling = async () => {
const res = await fetch(`http://www.ktfs.or.kr/bbs/board.php?bo_table=schedule/`);
const resString = await res.text();
const decodedRes = await iconv.decode(new Buffer(resString), 'euc-kr'); // iconv가 utf-8 기준이므로 [utf-8 -> euc-kr : encode], [euc-kr -> utf-8 : decode]
console.log(decodedRes);}
...
- 한글이 깨졌던 부분이 또 다른 문자로 깨져보였다.
- 원인을 찾아보니 utf-8 문서로 저장하는 과정에서 뭔가 잘못된 경우 발생하는 현상이었다.
- fetch() 로 데이터를 받아오는 과정에서 blob 형태로 가져올 수 없어서, convert 중 utf-8로 변경된다고 함.
- blob 형태로 가져오기 위해서 rn-fetch-blob 라이브러리를 이용해야 한다고 함.
* reference : https://thewiki.kr/w/%E5%8D%A0%EC%8F%99%EC%98%99
2) rn-fetch-blob 라이브러리를 이용해 웹데이터를 받아와 보았다.
import RNFetchBlob from 'rn-fetch-blob';
...
const Crawling = async () => {
const res = await RNFetchBlob.fetch(
'GET',
`http://www.ktfs.or.kr/bbs/board.php?bo_table=schedule`,
{
'Content-Type': 'text/html',
},
);
const base64Res = await res.data;
console.log(base64Res);
...
- RNFetchBlob.fetch 로 웹데이터를 받아오면, base64로 인코딩된 데이터를 받아온다.
- 해당 라이브러리를 설치 후 사용하면, Require cycle warning 이 발생하는데 아래 방법으로 해결
https://bocoder.tistory.com/102?category=904878
3) base64로 인코딩된 데이터를 디코딩한다.
import base64 from 'base-64';
...
const Crawling = async () => {
const res = await RNFetchBlob.fetch(
'GET',
`http://www.ktfs.or.kr/bbs/board.php?bo_table=schedule`,
{
'Content-Type': 'text/html',
},
);
const base64Res = await res.data;
const base64Decode = base64.decode(base64Res);
console.log(base64Decode);
...
4) 디코딩된 데이터를 다시 iconv-lit 를 이용하여 euc-kr 디코딩을 진행하며, 이때 버퍼를 위해 Uint8Array 를 사용한다.
import base64 from 'base-64';
...
const Crawling = async () => {
const res = await RNFetchBlob.fetch(
'GET',
`http://www.ktfs.or.kr/bbs/board.php?bo_table=schedule`,
{
'Content-Type': 'text/html',
},
);
const base64Res = await res.data;
const base64Decode = base64.decode(base64Res);
const byteArray = new Uint8Array(base64Decode.length);
for (let i = 0; i < base64Decode.length; i++) {
byteArray[i] = base64Decode.codePointAt(i);
}
const decodedString = iconv.decode(byteArray, 'EUC-KR');
console.log(decodedString);
...
정상적으로 한글이 잘 나오며, ios/android 모두 잘 작동한다.
코딩을 react-native 로 시작했다보니 encode/decode 부분이 익숙치 않아 고생을 많이 했다.