저번 글에 3트가 희망이 보인다.
CORS 에러는 IG 서버가 아니라 브라우저가 한다는 사실을 알게되었다.
어? 그러면 express 서버 띄워서 보내면 되겠네?
cctx라는 라이브러리를 이용해 크립토 트레이딩 봇을 만들어보려고 한번 해봤던게 정말 다행이다.
정말 간단했다.
하지만, 저번 글에서 얘기했던
요청헤더에 들어가는 값 중에 어느 값이 요청하는 프로필의 고유 id인 줄 알았지만 여러 계정에서 동일하게 나오는 것을 보면 이게 내 계정의 고유 id인가 싶더라
이 문제가 남아있었다.
그래서 내 현재 작업용으로 쓰는 내 mac이 아닌 비어있는 window 컴퓨터로 달려가 크롬 인터넷 데이터도 날리고 시크릿 창으로 켜서 동일한 requset를 확인해봤다.
응? 여기서도 동일하다.
적어도 로그인 했던 내 개인 계정의 고유 코드는 아니라는 소리 희망이 보인다!
이게 어디 나온 걸 찾아서 한 게 아니라 나도 우연히 돼서 혹여나 IG 정책에 어긋날까 봐 자세한 end point와 값들은 대충 바꿔서 적어놨다.
조금 더 찾아보고 문제가 없다고 판단되면 다시 수정해둘 생각이다.
우선 테스트를 위해서 간단하게 서버를 띄웠다.
// server.js
const express = require('express');
const app = express();
const PORT = 8080;
app.get('/', function (req, res) {
res.sendFile(process.env.PWD + '/src/index.html');
});
app.use(express.static('src'));
app.listen(PORT, () => {
console.log(`running server port: ${PORT}`);
});
클라이언트랑 서버 포트를 다르게 해줘도 상관없지만 그러면 proxy 처리를 해줘야했다. 그래서 그냥 동일 포트로 띄웠다.
이제 저번글 3트에서 봤던 End_Point로 fetch를 해보자
// server.js
const fetch = require('node-fetch'); // npm i --save node-fetch
const INSTAGRAM_API_ENDPOINT = 'https://www.instagram.com/~~~';
app.get('/getFeedData', async (req, res) => {
try {
const { ig_name, ig_app_id } = req.headers;
const url = `${INSTAGRAM_API_ENDPOINT}?username=${ig_name}`;
const options = { headers: { '???': ig_app_id }};
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(response.status);
}
const data = await response.json();
res.json(data.data);
} catch (error) {
console.error(`Error from Server: ${error.message}`);
res.status(Number(error.message)).json({
errorMessage: '서버에 일시적인 오류가 발생했습니다.',
errorCode: error.message,
});
}
});
정상적으로 출력 된다. 서버와 브라우저 보안 정책에 무지했던 나 자신을 반성하며 다시 차근차근 공부해 봐야겠다는 생각이 든다.
사실 저기 catch문 에러처리도 아래와 같이 가능하다.
// server.js
// ...
catch (error) {
next(error)
}
app.use((err, req, res, next) => {
console.error(`Error from Server: ${err.message}`);
res.status(err.status || 500).json({
errorMessage: '서버에 일시적인 오류가 발생했습니다.',
errorCode: err.status || 500,
});
});
찾아보니 express 미들웨어라는대 next()에 파라미터를 던지면 무조건 에러로 처리해서 에러 핸들링이 가능하다고 한다. 근데 이거는 아직 잘 모르기도하고 지금은 테스트가 우선이니 일단은 구현 후 공부하려고 주석처리만 해두고 사용하진 않았다. 모르는 코드를 그대로 썼을때 에러를 뿜어버리면...ㅠ
여기는 그래도 익숙한 편이다.
// index.js
async function getRestaurant(ig_name, ig_app_id) {
try {
const request = fetch('/getFeedData', { headers: { ig_name, ig_app_id } });
const response = await request;
if (!response.ok) {
const { errorMessage, errorCode } = await response.json();
throw new Error(errorMessage);
}
const result = await response.json();
const { user } = result;
const firstPost = user.edge_owner_to_timeline_media.edges[0].node;
const menuText = firstPost.edge_media_to_caption.edges[0].node.text;
console.log(menuText);
return menuText;
} catch (error) {
console.error('Error from Client:', error.message);
}
}
getRestaurant('restaurant_name', 000000000000);
결과
예! 근데 이게 아직 제대로 안정성이 검증이 되진 않아서 며칠간은 로컬에서 혼자 테스트 해볼 예정이다.
마지막으로 업체가 여러 곳이니까 코드를 조금만 더 수정하고 마쳐야겠다.
// index.js
const restaurant1 = { ig_name: 'restaurant1', ig_app_id: 0000000000 };
const URL = '/getFeedData';
async function getRestaurant1() {
const response = await useFetch(URL, restaurant1);
const firstPost = response.edge_owner_to_timeline_media.edges[0].node;
const menuText = firstPost.edge_media_to_caption.edges[0].node.text;
console.log(menuText);
}
async function useFetch(url, headers) {
try {
const request = fetch(url, { headers });
const response = await request;
if (!response.ok) {
const { errorMessage, errorCode } = await response.json();
throw new Error(errorMessage);
}
const result = await response.json();
const { user } = result;
return user;
} catch (error) {
console.error('Error from Client:', error.message);
}
}
getRestaurant1();
하다 보니 아래처럼 콜백을 넣어서 사용도 가능할 거 같은데 뭐가 더 나을지는 아직 테스트라 잘 몰라서 기록으로만 남겨둔다
// index.js
const restaurant1 = { ig_name: 'restaurant1', ig_app_id: 0000000000 };
const URL = '/getFeedData';
async function getRestaurant1() {
await useFetch(URL, restaurant1, (result) => {
const { user } = result;
const firstPost = user.edge_owner_to_timeline_media.edges[0].node;
const menuText = firstPost.edge_media_to_caption.edges[0].node.text;
console.log(menuText);
});
}
async function useFetch(url, headers, processResult) {
try {
const request = fetch(url, { headers });
const response = await request;
if (!response.ok) {
const { errorMessage, errorCode } = await response.json();
throw new Error(errorMessage);
}
const result = await response.json();
processResult(result);
} catch (error) {
console.error('Error from Client:', error.message);
}
}
getRestaurant1();
내가 찾지 못 했던 건지 어디 문서에도 나와있지 않았다. 우연히 발견했을 뿐. 운이 좋았다.
이번 주엔 테스트와 더 자세한 정보를 검색해 보며 안정성을 검증해 봐야겠다.