- cafe24라는 호스팅을 이용한 쇼핑몰 운영자들의 자사몰 홈페이지에 플로팅버튼을 띄우는 작업을 한다.
인증코드 발급
- 우선 쇼핑몰 운영자가 앱을 최초 실행시키면
- 클라이언트에서 cafe 24측에 인증코드를 요청한다.
- 이때 필요한 정보는
- {mallid} : 해당 쇼핑몰ID를 입력합니다.
- {client_id} : 개발자 센터에서 생성한 앱의 client_id를 입력합니다.
- {state} : 위변조 방지를 위해 입력하는 값으로 코드 반환시 같은 값이 반환됩니다.
- {redirect_uri} : 개발자 센터에서 생성한 앱의 Redirect URL을 입력합니다.
- {scope} : 해당 접근 토큰으로 접근할 리소스 서버의 권한을 입력할 수 있습니다.
- 이렇게 5가지인데
- 이 정보들을 통해 cafe24 측에서 제시한
GET 'https://{mallid}.cafe24api.com/api/v2/oauth/authorize?response_type=code&client_id={client_id}&state={state}&redirect_uri={redirect_uri}&scope={scope}'
- 로 api를 호출하면
HTTP/1.1 302 Found
Location: {redirect_uri}?code={authorize_code}&state={state}
- 이런식으로 응답을 준다.
액세스 토큰 발급
- 이후 발급받은 인증 코드를 이용해서 cafe24로부터 액세스 토큰을 발급받을 수 있다.
curl -X POST \\
'https://{mallid}.cafe24api.com/api/v2/oauth/token' \\
-H 'Authorization: Basic {base64_encode({client_id}:{client_secret})}' \\
-H 'Content-Type: application/x-www-form-urlencoded' \\
-d 'grant_type=authorization_code&code={code}&redirect_uri={redirect_uri}'
- 여기서의 {code}가 위에서 발급받은 인증코드이다.
- 이렇게 하면 앞으로의 cafe24 api를 호출할 때 사용할 액세스 토큰을 발급 받을 수 있다.
HTTP/1.1 200 OK
{
"access_token": "0iqR5nM5EJIq..........",
"expires_at": "2021-03-01T14:00:00.000",
"refresh_token": "JeTJ7XpnFC0P..........",
"refresh_token_expires_at": "2021-03-15T12:00:00.000",
"client_id": "BrIfqEKoPxeE..........",
"mall_id": "yourmall",
"user_id": "test",
"scopes": [
"mall.read_order",
"mall.read_product",
"mall.read_store",
"...etc...",
],
"issued_at": "2021-03-01T12:00:00.000"
}
- refresh_token이 있는 것을 보면 알 수 있지만 cafe24의 액세스 토큰은 2시간이 제한시간이며 그 시간이 지나면 같이 발급 받은 리프레쉬 토큰을 통해 액세스 토큰을 다시 발급받을 수 있다.
- 이 레프레쉬 토큰은 제한시간이 2주인데, refresh token 만료전에 요청을 하면 갱신된 access token과 갱신된 refresh token이 함께 반환된다.
- 기존 refresh token은 만료처리되어 사용할 수 없다.
scripttags api 호출
- 이제 cafe24측의 scripttags api를 봐보자.
//스크립트태그를 쇼핑몰의 특정 화면에 설치할 수 있습니다.
curl -X POST \\
'https://{mallid}.cafe24api.com/api/v2/admin/scripttags' \\
-H 'Authorization: Bearer {access_token}' \\
-H 'Content-Type: application/json' \\
-H 'X-Cafe24-Api-Version: {version}' \\
-d '{
"shop_no": 1,
"request": {
"src": "<https://yourdomain-sample.com/sample-script.js>",
"display_location": [
"PRODUCT_LIST",
"PRODUCT_DETAIL"
],
"exclude_path": [
"/product/list.html",
"/product/detail.html"
],
"skin_no": [
3,
4
],
"integrity": "sha384-UttGu98Tj02YSyWJ5yU0dHmx4wisywedBShWqEz+TL3vFOCXdeMWmo6jMVR8IdFo"
}
}'
- 이 api를 호출하면(쇼핑몰 운영자의 mallid와 위에서 발급받은 access_token이 필요하다.)
- body의 request의 src값인 script를 쇼핑몰운영자의 자사몰에 설치할 수 있다.
- 이렇게 보면 상당히 쉬워보이지만 몇가지의 문제사항들을 해결해야한다.
cors
- 별다른 설정없이 호출한다면 분명 cors에러가 발생할 것이다.
- 우선 이에 대한 cafe24측의 답변은 다음과 같다.
안녕하세요.
카페24 앱스토어 운영팀입니다.
Script Tag API의 src로 지정하는 스크립트 경로는 카페24에서 해당 스크립트 경로에 접근하는 시점에 src에서의 CORS (상이한 오리진) 정책을 따르고 있습니다.
즉, 스크립트 파일이 카페24 (동일 도메인) 에 상주하는게 아닌 외부의 상이한 도메인 (이 경우 <https://aim.xxxxxx.ac.kr>) 에 있는 관계로 ys.js 라는 스크립트를 호스팅하는 <https://aim.xxxxxx.ac.kr> 서버의 CORS 설정을 access-control-allow-origin: * 로 맞춰주셔야 합니다.
아래 예시와 같이 CURL을 했을때 응답 헤더에 Access-Control-Allow-Origin: * 이 반환되어야 합니다.
-----------------------------------------
> curl -i <https://cafe24.dev>
-----------------------------------------
HTTP/1.1 200 OK
Date: Thu, 03 Nov 2022 06:22:25 GMT
Server: Apache/2.4.54 () OpenSSL/1.0.2k-fips
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 41
ETag: W/"29-YT2GwxxxxxxxxxxxxxSrFzA0"
Access-Control-Allow-Origin: *
감사합니다.
- 이 부분에서 알 수 있는 해결방법은 서버를 경유해서 api를 호출하는 아주 정석적인 방법이다.
- 이렇게 하면 대부분 해결된다.
- 다만 나의 경우 해결되지 않았는데 그 이유와 해결방법을 아래서 적을 수 있도록 하겠다.
- 추가적으로 만약 서버를 경유하지 않고 호출하려면
- https://cors-anywhere.herokuapp.com/corsdemo
- 를 사용하면 좋다
- 사용방법은 api의 조건중 url의 앞에 https://cors-anywhere.herokuapp.com/를 붙이기만 하면 된다.
- ex) https://cors-anywhere.herokuapp.com/https://xxxxxxx123.cafe24api.com/api/v2/admin/scripttags
- 또한 위에 적은 heroku corsdemo 사이트에서 request temporary access to the demo server 를 눌러야하며 그 유효기간은 하루인지라 계속 사용하려면 하루에 한번씩은 눌러줘야 하는 단점이 있다.
- 사람들이 너무 많이 몰려 이런 정책을 취한 것으로 알고 있다.
- 다만, 위에서의 하루 제한 기간과 더불어 정상적인 방법은 아니므로 서버를 경유해서 호출하는 방법을 해야하고 이 방법은 테스트 용도로만 사용해야 한다.
유저 → 클라이언트 → 서버 → cafe24
- 유저가 프론트개발자가 만든 버튼(나의 경우에는 자사몰에 버튼을 설치하는 기능이었다.)을 클릭하면 클라이언트에서는 서버에게 cafe24로 scripttags api를 호출하라고 하는 api 를 호출한다.
- 단, 여기서 우리만의 특이한 점은 버튼의 디자인과 위치가 고정값이 아닌 유저가 변경할 수 있는 값이었다는 점이다.
- 이제 새로운 문제는 cafe24측이 제공한 scripttags api에서 어떻게 디자인 정보와 위치 정보를 전달하여 자사몰에 반영하냐는 점이다.
api 호출시 데이터(디자인, 위치)를 전달하는 법
- 결론부터 얘기하면 쿼리스트링밖에 없다.
- 다시 cafe24의 scripttags를 보면
//스크립트태그를 쇼핑몰의 특정 화면에 설치할 수 있습니다.
curl -X POST \\
'https://{mallid}.cafe24api.com/api/v2/admin/scripttags' \\
-H 'Authorization: Bearer {access_token}' \\
-H 'Content-Type: application/json' \\
-H 'X-Cafe24-Api-Version: {version}' \\
-d '{
"shop_no": 1,
"request": {
"src": "<https://yourdomain-sample.com/sample-script.js>",
"display_location": [
"PRODUCT_LIST",
"PRODUCT_DETAIL"
],
"exclude_path": [
"/product/list.html",
"/product/detail.html"
],
"skin_no": [
3,
4
],
"integrity": "sha384-UttGu98Tj02YSyWJ5yU0dHmx4wisywedBShWqEz+TL3vFOCXdeMWmo6jMVR8IdFo"
}
}'
- src를 제외하고는 그 어디에도 데이터를 넣을만한 곳이 없다..
- 따라서
"<https://yourdomain-sample.com/sample-script.js?left=11&bottom=75&opacity=1>"
- 이런식으로 넣으면 된다.
- 그렇다면 이제 다시 문제는 이렇게 삽입한 쿼리스트링을 어떻게 자사몰의 버튼에 적용시키는가이다.
해결 방법은 document.getElementsByTagName("script")
- 흐름을 보자면
- 유저가 버튼을 누르고
- 클라이언트가 서버에 api 호출하고 (body에 데이터포함)
- 서버가 cafe24 api 호출한다(src의 url에 쿼리스트링으로 데이터 포함)
- 그 다음은 ???
- 이렇게 하면 해결법은
- 설치되는 스크립트에서 자동으로 script들을 읽고
- 그 url에서 쿼리스트링에 포함된 데이터를 읽어
- 그 정보로 자사몰에 동적으로 자식태그를 넣어야 한다.
- 이걸 실현하려면 설치되는 script가 자동으로 실현되어야 하므로 즉시 실행 함수를 사용한다.
익명 즉시 실행 함수
(function (x) {
console.log(x*x);
})(2);
(function (x) {
console.log(x*x);
}(2));
- 그 다음 함수의 내부에 document.getElementsByTagName("script") 를 사용한다.
- 그러면 현재 페이지에서 사용된 script들이 배열로 주르륵 나오는데 이 cafe24 api를 통해 설치된 스크립트는 제일 마지막에 나오게 되고
- 자세한 사항은 https://sjpison.tistory.com/127 여기서 확인하자.
function getJsPath() { var scriptList = document.getElementsByTagName("script"); var fileName = scriptList[scriptList.length - 1].src; var token = fileName.split('/'); var str = ''; for(var i=0; i<token.length-1; i++) { str += token[i]; if(token.length-2 != i) str += '/'; } return str; } path = getJsPath(); //현재 js 파일이 불러지는 시점에서는 해당 js 파일이 가장 마지막 script 문이라는 거죠~ //즉 이 함수가 유효하려면 js 파일의 로딩 시점에서 함수가 실행되어야 합니다. //마지막에 'path = getJsPath();' 가 필요한 이유이기도 합니다~
- 거기서 쿼리스트링을 읽어 그 데이터들을 동적으로 버튼의 css style에 템플릿 리터럴로 넣어주면 된다.
- 이 과정을 정리하면
- document.getElementsByTagName("script");로 쿼리스트링 데이터 가져오기
- let i = document.createElement("div")로 div태그 만들기
- ([i.id](<http://i.id/>) = "pops") 로 i에 id 만들어주기
- document.body.appendChild(i) 로 body에 태그 추가하기
- document.getElementById("pops").innerHTML 로 디테일 더하기 이다.
추가로 발생하는 문제
- 이 과정대로 했을 경우 서버에서 422 request parameter 에러가 발생할 수 있다.
- 이 에러를 cafe24 측은
422
An invalid request is entered.
Unprocessable Entity
조회/ 처리 요청시 다음에 해당하는 경우
- 필수 파라미터 누락
- 정해진 기본값과 불일치/ 올바른 입력값이 아님
API 문서를 참고하여 누락된 파라미터 또는 유효하지 않은 값이 있는지 확인하세요.
- 라고 설명하는데 많은 삽질 끝에 알게 된 것은 우선 src에 쿼리스트링을 넣을 때 템플릿 리터럴을 쓰면 안된다는 것이다.
- 그럼 어떻게 쓰냐고?
- 과거의 방법을 쓰면 된다.
`https://yourdomain-sample.com/sample-script.js?left=${left}&bottom=${bottom}&opacity=${opacity}`
const url = "<https://yourdomain-sample.com/sample-script.js?left=>" + left + "&bottom=" + bottom + "&opacity=" + opacity;
- 와 같이 하면 ‘를 안쓰게 되고 따라서 422에러를 피할 수 있게 된다.
출처
https://velog.io/@himprover/이제는-모던-자바스크립트를-알아야지-템플릿-리터럴-문자열-조합
https://developers.cafe24.com/docs/api/#api-limit
https://developers.cafe24.com/docs/ko/api/admin/#create-a-script-tag
https://developers.cafe24.com/docs/ko/api/admin/#get-authentication-code
https://developers.cafe24.com/docs/ko/api/admin/#get-access-token-using-refresh-token
https://mine-it-record.tistory.com/495
https://developers.cafe24.com/app/front/app/develop/oauth/process
https://developers.cafe24.com/app/front/app/develop/api/errors
'develop' 카테고리의 다른 글
react에서 텍스트 삽입 및 줄바꿈 설정하는법 with 템플릿 리터럴 (0) | 2023.04.16 |
---|---|
react input에 숫자만 쓸 수 있게 하는법 (0) | 2023.04.10 |
useState의 비동기 문제 - useRef (0) | 2023.04.07 |
useState의 비동기 문제 - 함수형 업데이트 (0) | 2023.03.29 |
useState의 비동기 문제 - 원인 (0) | 2023.03.26 |