Skip to content

Instantly share code, notes, and snippets.

@brownsoo
Last active September 26, 2023 07:35
Show Gist options
  • Save brownsoo/f5fc9f19fd910da087ffcacb3bff4b21 to your computer and use it in GitHub Desktop.
Save brownsoo/f5fc9f19fd910da087ffcacb3bff4b21 to your computer and use it in GitHub Desktop.
토큰 갱신을 위한 Ajax 목업
class Rest {
static apiBaseUrl = '';
static getApiHeader({withoutContentType = false} = {}) {
const header = {};
header['reqVersion'] = 2;
// if (authentic) {
// header['Authorization'] = this.getAuthToken();
// }
if (!withoutContentType) {
header['Content-Type'] = 'application/json;charset=utf-8';
}
return header;
}
static getAuthToken() {
const t = getToken();
if (t) {
return 'Bearer ' + t;
}
return '';
}
// document 로드시 한번만 수행되도록 함.
static isAddedAuthFilter = false;
static maxExpiredAuthorizationRetries = 2;
// https://api.jquery.com/jquery.ajaxprefilter/
static makeAuthFilter() {
if (this.isAddedAuthFilter) return;
this.isAddedAuthFilter = true;
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
// 무한 반복 방지
originalOptions._retry = isNaN(originalOptions._retry)
? Rest.maxExpiredAuthorizationRetries
: originalOptions._retry - 1;
console.log('originalOptions._retry=' + originalOptions._retry
+ ' originalOptions.isAuthentic=' + originalOptions.isAuthentic);
if (originalOptions.isAuthentic) {
jqXHR.setRequestHeader('Authorization', Rest.getAuthToken());
}
// 본래 오류 콜백 저장
if (originalOptions.error) {
originalOptions._error = originalOptions.error;
}
// 현재 오류 콜백 오버라이드
options.error = $.noop();
// 모든 재요청이 완료되면, 결과를 전송하도록 deferred object 생성
const df = $.Deferred();
jqXHR.done(df.resolve);
// 요청 실패 처리
jqXHR.fail(async function () {
const args = Array.prototype.slice.call(arguments);
if (jqXHR.status === 401 && originalOptions._retry > 0) {
try {
// 토큰 갱신 요청
await Rest.refreshToken();
// 갱신 성공 후 재시도
$.ajax(originalOptions).then(df.resolve, df.reject);
} catch (error) {
if (originalOptions._retry > 0) {
// 갱신 요청 실패 후 재시도
$.ajax(originalOptions).then(df.resolve, df.reject);
} else {
df.reject(error);
}
}
} else {
// 본래 오류 콜백 추가
if (originalOptions._error) {
df.fail(originalOptions._error);
}
df.rejectWith(jqXHR, args);
}
return df.promise(jqXHR);
});
});
}
/**
* 토큰 시간이 유효한지 체크
* @returns {boolean}
*/
static validateTokenExp() {
const token = getToken();
const tokenExp = getCookie('tokenExp');
if (token && tokenExp) {
const expireDate = new Date(tokenExp * 1000);
const now = new Date();
return expireDate > now;
}
return true;
}
static correctUrl(url) {
if (!url || typeof url !== 'string') {
throw new Error('url 이 이상해!!');
}
if (url.indexOf('http') < 0) {
if (url[0] !== '/') {
url = '/' + url;
}
return this.apiBaseUrl + url;
}
return url;
}
static refreshToken() {
const df = $.Deferred();
let headers = this.getApiHeader();
headers['Authorization'] = getRefreshToken();
$.ajax({
headers: headers,
method: 'GET',
url: this.correctUrl('/auth/refresh'),
cache: false,
}).done(function onSuccessRefreshToken(res) {
console.log(res);
if (!res.success) {
df.reject(new TokenRefreshError());
} else {
const {accessToken, refreshToken} = res.data.tokens;
setToken(accessToken, refreshToken);
df.resolve(accessToken);
}
}).fail(function onFailRefreshToken(jqXHR, textStatus, errorThrown) {
console.log([jqXHR, textStatus, errorThrown]);
df.reject(new TokenRefreshError());
});
return df.promise();
}
static createRequest(options) {
this.makeAuthFilter();
return $.ajax(options).then(function (res) {
if (!res.success) {
throw KfError.createResponseError(res, options.url);
}
return res;
}).catch(function (jqXHR, textStatus, errorThrown) {
throw KfError.convertKfError(jqXHR, options.url);
});
}
static get(url, data = undefined, authentic = true) {
const options = {
url: this.correctUrl(url),
headers: this.getApiHeader(),
method: 'GET',
data: data,
cache: false,
isAuthentic: authentic,
};
return this.createRequest(options);
}
static put(url, data = undefined, authentic = true) {
const options = {
url: this.correctUrl(url),
headers: this.getApiHeader(),
method: 'PUT',
cache: false,
isAuthentic: authentic,
};
if (data) {
options.data = JSON.stringify(data);
}
return this.createRequest(options);
}
static post(url, data = undefined, authentic = true) {
const options = {
url: this.correctUrl(url),
headers: this.getApiHeader(),
method: 'POST',
cache: false,
isAuthentic: authentic,
};
if (data) {
options.data = JSON.stringify(data);
}
return this.createRequest(options);
}
static delete(url, data = undefined, authentic = true) {
const options = {
url: this.correctUrl(url),
headers: this.getApiHeader(),
method: 'DELETE',
cache: false,
isAuthentic: authentic,
};
if (data) {
options.data = JSON.stringify(data);
}
return this.createRequest(options);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment