💻 Frontend
Axios, Fetch를 통해 req header에 timezone 보내기
[목차]
1) What is Axios1-1) HTTP란?1-2) What is Promise? 1-3) Axios 이해하기1-4) What is Fetch?2) Axios.vue, Fetch.vue 구현2-1) Axios로 구현 (with CORS)What is SOPWhat is CORS2-2) Proxy 설정을 통한 구현what is proxy?2-3) Request header에 TimeZone 보내기
1) What is Axios
Axios는 프로미스기반의 HTTP 통신 라이브러리이다.
그렇다면 HTTP 통신과 Promise라는 개념을 먼저 이해해야한다.

[공식문서 해석] axios는 브라우저,node.js를 위한 프로미스 기반의 HTTP 비동기통신 라이브러리이다. node에서는 http 모듈을 사용하고, 브라우저에서는 XMLHttpRequests를 사용한다.
1-1) HTTP란?

Http는 통신 프로토콜(규칙)이다.
풀어서 말하면 HTML,image 등의 리소스들을 특정 형식에 맞게 주고 받는 것
HTTP 추가설명
Http request의 구조

- Request Line (메서드, 프로토콜, 버전)
- HTTP 메서드를 사용해 서버가 수행할 동작을 나타냄
- 요청 타겟(프로토콜, 포트, 도메인 등)을 타나냄.
- 응답 메시지에 사용할 HTTP 버전을 알려줌
- Header (general, request, entity)
- General header : 요청과 응답에 모두 적용되지만 데이터와 관련이 없는 것
- Request header : 요청하는 클라이언트에 대한 자세한 정보를 포함하는 헤더 (Host, User-Agent, Cookie)
- Entity header : 콘텐츠의 길이나 MIME 타입과 같이 Entity Body에 대한 자세한 정보를 포함 (Content-Type, Content-Length 등)
- Body
- 특정 리소스를 포함해서 Request를 보낼 때 리소스가 포함되는 곳.
- http 구조의 마지막
Http response의 구조

- Status line : 프로토콜 버전, Status, Status Text
- Header : General header, Response header, Entity header
- Body : response의 마지막 부분에 들어갑니다. (content-type, content-length)
XMLHttpRequset(XHR)

http 요청과 응답은 XMLHttpRequest라는 함수를 통해서 진행한다.
해당 함수를 서버와 통신하는 과정은 AJAX라는 비동기 통신 개발방식을 통해서 이해할 수 있다.
XMLHttpRequest(XHR)
XMLHttpRequest 객체는 서버와 통신하기 위한 자바스크립트 API
서버 처리방법, 이벤트 핸들러, 헤더, 및 요청에 따른 처리 등 여러가지 조건을 달아줘야함.
아래는 xhr 코드의 예시
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
위와 같이 XML을 주고 받는 방식을 Ajax라고 부른다.
Ajax는 과거 자바스크립트가 Jquery와 함께 사용될 때 흥했던 방식
Ajax는 Asyncronous Javascript and XML의 약자로 XML이라는 마크업언어를 비동기적으로 주고받는 개발 방식.
XML이라고 표기되어있지만, 다양한 형태의 리소스를 주고 받을 수 있음.
1-2) What is Promise?
Promise는 비동기 작업의 Resolve와 Reject 상태를
콜백함수로 갖는 객체입니다.
비동기작업과 그 역사 (callback, promise, async/await)
비동기 처리 프로세스
동기는 순차적으로 처리를 한다.
비동기는 동시에 여러가지 작업을 한다.
오래 걸리는 작업을 다른 곳에 두고, 작업이 끝나면 다시 실행하는 것.
근데 자바스크립트는 싱글스레드 언어이다. 따라서 하나의 스레드(콜스택)에서 순차적으로 처리를 하는데,
어떻게 오래 걸리는 작업을 따로 다룰 수 있을까?
자바스크립트는 dom과 서버통신, Timeout 등 웹에서 제공하는 API와 따로 동작한다.


위와 같은 코드가 있다고 한다면,
-----console.log에 찍힌 순서-----
0
1
2
3초 걸리는 for문 끝!
main 끝!
1.5초 타이머 끝!Callback 함수의 비동기 활용
이러한 비동기 처리는 이전에는 Callback 함수를 통해서 처리한다. 그렇다고 Callback = 비동기는 아니다.
애초에 Callback은 다중작업을 하기 위해서 함수의 인자로 함수를 넘겨주는 함수다.

이 때 비동기 작업(Web API 런타임환경을 이용한 작업)을 함수로 넘겨주는 패턴이 유용하게 사용되면서 callback함수를 비동기적으로 활용한 것이다.
바로 아래와 같은 코드이다.

그런데 위의 코드가 어떠한가? 여러가지의 비동기 콜백함수가 여러 개가 된다면 코드의 가독성이 굉장히 떨어질 것이다.
Promise의 등장
promise는 약속이다. (scala → future)
resolve와 reject라는 콜백을 넘기는 생성자함수이다.
Promise는 다음 중 하나의 상태를 가집니다.- 대기(pending): 이행하지도, 거부하지도 않은 초기 상태.
- 이행(fulfilled): 연산이 성공적으로 완료됨.
- 거부(rejected): 연산이 실패함.

promise가 어떻게 작업을 하냐면 아래의 코드 예시를 보면 더 직관적으로 이해할 수 있다.

위의 코드를 보면 new Promise()라는 함수에
- resolve : 성공했을 때 실행 함수
- reject : 실패했을 때 실행 함수
두 가지의 콜백을 던져주고 .then()메서드로 콜백의 값을 전달받는 구조이다.
둘 다 모두 비동기 작업이 잘 수행되는 것을 볼 수 있다.
Chaning
Chaning은 promise의 가장 큰 장점 중에 하나이다. 기존의 콜백형태로 체이닝 했을 때의 불편함을 아래의 메서드로 굉장히 직관적으로 사용할 수 있다.
- .then() : 실행된 콜백함수의 resolve 결과 값을 받아 작업하는 메서드
- .catch() : 실행된 콜백함수의 reject 결과 값을 받아 작업하는 메서드
- .finally() : 설정 콜백함수가 모두 끝날 때 (resolve,reject 상관없이) 작업하는 메서드
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);특히 예외처리의 경우 기본적인 try, catch로 promise를 묶는 것이 아니라, promise에 해당되는 함수에 직접적으로 catch문을 달아줘야함.
Promise.all()
Promise.all()은 여러 프로미스의 결과를 집계할 때 사용함.
모든 비동기 작업이 이행되어야만 value값으로 각 Promise의 value를 배열로 담는 형태로 진행된다.

이는 모든 값 중에 하나가 reject될 경우, 에러를 낸다.

Promise.race()
이런 promise.race는 가장 빨리 끝난 promise의 결과값만을 return하는 메서드이다.

Async/Await
Async는 기본적인 함수에 Async를 붙여주면 결과 값이 promise로 반환되는 장치
Await는 특정 작업이 끝날 때 까지 기다리게 하는 장치

위의 코드는 await없이 적용하는 것.

위의 코드는 await를 적용해서 promise를 변수에 할당함.
1-3) Axios 이해하기
다시 axios의 정의를 살펴보면 Axios란, 프로미스 기반의 HTTP 통신을 하는 라이브러리이다.
- 프로미스를 자동으로 만들어주기 때문에 코드 간소화가 가능
- 메서드를 통해 서버 통신을 직관적으로 할 수 있음.
그렇다면 어떻게 프로미스화한다는 것인지 코드를 보면 알 수 있다.
// ID로 사용자 요청
axios.get('/user?ID=12345')
// 응답(성공)
.then(function (response) {
console.log(response);
})
// 응답(실패)
.catch(function (error) {
console.log(error);
})
// 응답(항상 실행)
.then(function () {
// ...
});오잉 .then()이랑 .catch()가 있네.
아 그러면 async처럼 http 통신을 할 때 axios를 이용하면 해당 함수를 promise로 바꿔주는 것이구나.
Axios 추가 설명
Axios의 기본 구조
1) config 전달
// 원격 이미지 GET 요청
axios({
method:'get',
url:'http://bit.ly/2mTM3nY',
responseType:'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});- method : get,post 등 요청 메서드를 전달
- url : xml을 보낼 url 입력
- data : requset Body으로 전송할 데이터
- params : 요청과 함께 전송될 URL 매개변수
- 그 외 (timeout, withCredentails 등의 config options가 있음)
2) axios method
- 인스턴스 생성(create)
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
headers: { 'X-Custom-Header': 'foobar' },
timeout: 1000,
});- 인스턴스 메서드
axios.get(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
axios.delete(url[, config])
axios.request(config)
axios.head(url[, config])
axios.options(url[, config])
axios.getUri([config])- 응답 스키마
{
// `data`는 서버가 제공한 응답(데이터)입니다.
data: {},
// `status`는 서버 응답의 HTTP 상태 코드입니다.
status: 200,
// `statusText`는 서버 응답으로 부터의 HTTP 상태 메시지입니다.
statusText: 'OK',
// `headers` 서버가 응답 한 헤더는 모든 헤더 이름이 소문자로 제공됩니다.
headers: {},
// `config`는 요청에 대해 `axios`에 설정된 구성(config)입니다.
config: {},
// `request`는 응답을 생성한 요청입니다.
// 브라우저: XMLHttpRequest 인스턴스
// Node.js: ClientRequest 인스턴스(리디렉션)
request: {}
}3) axios.interceptors
// 요청 인터셉터 추가
axios.interceptors.request.use(
function (config) {
// 요청을 보내기 전에 수행할 일
// ...
return config;
},
function (error) {
// 오류 요청을 보내기전 수행할 일
// ...
return Promise.reject(error);
});
// 응답 인터셉터 추가
axios.interceptors.response.use(
function (response) {
// 응답 데이터를 가공
// ...
return response;
},
function (error) {
// 오류 응답을 처리
// ...
return Promise.reject(error);
});axios에서 유용하게 사용되는 기능 중 하나가 interceptor 기능이다.
then이나 catch로 처리되기 전에 요청이나 응답을 가로채는 기능인데, 이를 통해 토큰 갱신 혹은 예외처리 등의 작업을 할 수 있다.
1-4) What is Fetch?
Fetch는 비동기 네트워크 통신을 위한 자바스크립트 API이다.
XMLHttpRequest와 비슷한데, result로 promise를 반환한다는 차이가 있다.
Fetch의 기본 사용법
- fetch() 메소드는 인자로 url과 options을 전달할 수 있다.
fetch(url,{options})- options 종류
method : get, post, delete, put, patch
headers, body : header, body(data)
mode : 요청에 사용하는 모드 (same-origin, cors, no-cors)
credentials : 자격 증명으로 브라우저가 수행하는 작업 제어
(쿠키, http인증)
redirect : 특정 응답에 따라 페이지를 redirect 시키는 작업
(follow, manual, error)
- 응답 response data
fetch('http://example.com/movies.json')
.then((response) => response.json())
.then((data) => console.log(data));
- Json 파일로 전환
- Json 파일로 전환을 하면 Promise가 반환이 된다.
- 해당 프로미스에 대한 resolve, reject결과를 then 메서드로 연결을 해주면 해당 반환 값이 나오게 된다.


2) Axios.vue, Fetch.vue 구현
2-1) Axios로 구현 (with CORS)
What is SOP
SOP(Same-Origin Policy)란 자신과 같은 출처만 서버로부터 데이터 요청하여 받을 수 있도록 하는 정책이다.
예를 들어, google.com에서 naver.com으로 서버의 데이터 요청을 할 수 없게 브라우저에서 막아놓은 것이다.
만들어진 이유는?
google에서 naver에 자유롭게 리소스를 요청하면 해당 서비스에 등록되어있는 정보를 빼내기가 굉장히 쉬워지기때문에, 같은 출처에서만 공유하게끔 막아놓은 것이다.
출처(origin)라는게 정확하게 뭐지?
- What is origin
- 출처는 scheme(protocol), host, port를 포함하는 url을 의미함.
- 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합친 것
https://google.com:443
https:// => protocol
googl.com => host
:443 => port( IE는 포트를 완전히 무시함..ㅎㅎ )

What is CORS
CORS(Cross-Origin Resource Sharing) 정책이란,
추가 HTTP헤더를 사용하여 다른 출처간 리소스를 공유할 수 있도록 하는 정책이다.
서버 통신 요청을 보낼 때 마다 origin으로 현재의 서버를 전달하고
서버에서는
Access-Control-Allow-Origin 을 설정을 통해 서버 통신이 가능한 Origin을 명시하고, 이 응답이 유효한 응답인지 아닌지 체크브라우저는 해당 값이 유효한 것만 체크함.
CORS의 3가지 방식
- preflight request
- 사전요청을 통해 access할 수 있는 origin은 8080이다
- 해당 요청과 다른 도메인은 바로 CORS 위반에 대한 에러를 뱉는다.
- 그러나, 사전요청은 성공했으나 본 요청에서 실패하는 경우도 있다. 이는 브라우저가 CORS 정책 위반 여부를 판단하는 시점이 예비 요청에 대한 응답시점 이후이기 때문에 사전요청의 실패 유무가 중요하지 않다.
- 응답 헤더에 유효한
Access-Control-Allow-Origin값이 존재하는가가 중요하다 - 그렇다면 왜 사전요청을 보낼까? 심지어 사전요청 시점도 제 멋대로이다..


- simple request

요청의 메소드는 GET, HEAD, POST 중 하나여야 한다.
Accept, Accept-Language, Content-Language,
Content-Type, DPR, Downlink, Save-Data,
Viewport-Width, Width를 제외한 헤더를 사용하면 안된다.
만약 Content-Type를 사용하는 경우에는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용된다.- credentialed request
- CORS는 다른 출처 간 통신에서 보안을 강화하고 싶을 때 사용하는 방법이다.
- credentials 옵션을 사용하면 3가지 옵션을 사용하여 설정할 수 있다.
- same-origin : 같은 출처 간 요청에만 인증정보
- include : 모든 요청에 인증 정보
- omit : 모든 요청에 인증 정보를 담지 않는다.
- 옵션을 설정이 되어있는지 어떻게 알 수 있는가
- 쿠키값을 설정해서 진행함.
CORS 해결법
- cors가 당연히 날 것이라는 가정을 했는데, 결과적으로는 이 가정이 잘못되었다..
- cors 해결을 위한 시도
- Access-Control-Allow-Origin 설정
- Credental true를 통해 인증된 요청을 사용
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods":
"GET,PUT,POST,DELETE,PATCH,OPTIONS",
"Access-Control-Allow-Credentials": "true",
},- 이미 서버측에서 header를 통해 allow 값을 설정했는데, 프론트에서 추가적으로 allow-origin 설정값을 바꿔주면 다른 초기화되는 것으로 추정..
- 위의 것들은 서버측에서 설정해야하는 것!
- 그냥 다 빼고 처음부터 다시 해보니까 되었다.
- CORS 해결법
- postman으로 되는지 확인
- api 주소를 잘못쓴 것이 아닌지
- 위의 3가지 시나리오를 검토해보기
- 프록시서버 구성 하기
- 백엔드에 문의
2-2) Proxy 설정을 통한 구현
what is proxy?
- proxy 구현
- Proxy 서버를 만든디는 것은 우회 서버를 만든다는 것
- 특정 요청의 이름으로 서버 요청을 보내면 프록시서버에서 다른 값으로 바꿔서 보내주는 것.

- webpack dev server
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'https://api.evan.com',
changeOrigin: true,
pathRewrite: { '^/api': '' },
},
}
}
}- vue에서 proxy 설정하기
Vue는 vue.config에서 웹팩을 자체적으로 하기 때문에 vue.config.js에서 동일하게 작성해주면 된다.
devServer: {
proxy: {
"/api": {
changeOrigin: true,
pathRewrite: {
"/api": "",
},
target: "https://dev.gateway.himedi.com/",
},
},
},2-3) Request header에 TimeZone 보내기
- 특정 메서드가 있는지 검토
- X-timezone-offset이라는 메서드가 있음.
- 자료를 서치했으나 timezone 조작이 어려움

- 쿠키값으로 보내보자
- headers에 timezone을 보내는 메서드가 분명 있을거야..
- 쿠키값으로 timezone을 설정하고 쿠키값을 읽어서 요청.
- 가능은한데 우선 너무 복잡하고, 쿠키값을 계속 바꿔줘야한다는 점이 있음.. 멘붕과 고민
- 그냥 header에 key,value 실어주기
export const api = axios.create({
baseURL: BASE_URL,
headers: {
"Time-Zone": new Date().getTimezoneOffset(),
},
validateStatus: (status) => {
return status < 500;
},
});참고)


