유미의 기록들

[React -4] 서버로 데이터 요청하고 받아오기 본문

MDLAB 기록/관리자페이지

[React -4] 서버로 데이터 요청하고 받아오기

지유미 2023. 5. 23. 23:54
728x90
반응형

서버로 데이터를 요청하고 받아오기 앞서 동기, 비동기 처리와 HTTP프로토콜에 대해 설명하겠다

2개 이상의 프로세스가 있을 경우에 동기, 비동기의 개념을 설명할 수 있다

프로세스 (Procecss) 운영체제로부터 자원을 할당받은 작업의 단위

 

동기 vs 비동기

 

동기 (Synchronous) 

요청을 보낸 후 응답을 받아야만 다음 동작이 이루어지는 방식 - 직렬적

 

어떤 일을 처리하는 동안 다른 일을 하지 못하고 기다려야 한다

따라서 일이 순차적으로 진행되며, Blocking이 발생한다. 

 

비동기 (Asynchronous)

프로세스의 완료를 기다리지 않고 동시에 다른 작업을 처리하는 방식 - 병렬적

어떠한 일을 처리하는 동안 다른 일을 할 수 있다

따라서 완료 순서가 보장되지 않으며 Blocking이 발생하지 않는다. 동기방식보다 빠르게 처리할 수 있다

 

 

JavaScript싱글스레드의 기반으로 프로세스를 처리하는 동기방식이라고 할 수 있다

하지만 비동기방식으로 처리해야 하는 작업이 있을 경우도 있다. 대표적으로 서버에 요청을 보내서 데이터를 불러오는 작업 등 무거운 작업을 처리 하는 시간 동안 다른 작업은 할 수 없다 따라서 이 경우에는 비동기 방식으로 처리해야 한다

스레드 (Thread) 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위

 

그럼 어떻게 비동기 방식으로 동작시킬 수 있을까?

 

1. 콜백함수 사용

 

 

A함수가 B함수를 호출하면서 응답후 처리 할 콜백함수를 알려주고 B함수가 완료 되었을 때 콜백함수가 호출된다

function CallBack(callback){
    function CallBack2(callback){
        function CallBack3(callback){
                    ...
        }
    }
}

 하지만  위의 코드와 같이 콜백지옥이 발생할 수 있다

 

 

2. Promise

콜백함수의 단점을 보완하여 비동기 처리 시점을 명확하게 표현가능하고 연속된 비동기 처리작업을 수정, 삭제, 추가하기 편하고 유연하다 

 

다음 중 하나의 상태를 가진다

* 대기 (pending) | 초기 상태

* 이행 (fulfilled) | 연산 성공 완료

* 거부 (rejected) | 연산 실패

 

 

비동기작업의 성공적인 완료 또는 실패와 그 결과 값을 나타낸다

 

 

3. Async, Await

기존의 콜백과 Promise의 단점을 보완하기 위해 나온 것으로 함수 앞에 async를 붙여 사용해야 하며 async안에서만 awiat를 사용가능하다

async function 함수명() {
  await 비동기_처리_메서드_명();
}

 

 

 

 

 

 

HTTP (Hyper Text Transfer Protocol)
프로토콜  컴퓨터 내부에서 또는 컴퓨터 사이에서 데이터의 교환방식을 정의하는 규칙체계

HTTP는 초기에는 웹 상의 하이퍼텍스트 형태의 문서를 전달하는데 주로 이용하였지만 현재는 이미지, 동영상, 음성 등 거의 모든 형식의 데이터를 전송할 수 있다

 

클라이언트 즉, 웹브라우저가 서버로 요청(request)을 하게 되면, 서버측은 응답(response)을 보내게 된다 

요청과 응답의 정보가 담긴 메시지를 HTTP 메시지라고 하며, 시작줄, 헤더, 본문으로 구성된다

 

 

Request 메시지 

요청 메소드로 GET인지 POST를 정하는데 POST일 경우만 본문(body)을 붙여서 전달한다

헤더(header)와 본문(body)는 빈 줄으로 구분한다

 

* GET  

정보를 요청하기 위해 사용되며 URL 주소 끝에 파라미터를 포함하여 전송한다

"?" 뒤에 변수명1=값 & 변수명2=값 형식으로 사용하면 된다. 즉, query부분에 해당한다 (query string)

⚠️ 파라미터로 데이터값이 노출되기 때문에 보안 측면에서 중요한 정보는 다루지 않는 것이 좋다

 

 

* POST

정보를 밀어넣기 위해 사용되며 전송할 데이터는 body에 담아서 전송한다

데이터의 내용이 눈에 보이지 않아 Get방식보다 보안적으로 안정적이다 하지만 개발자 도구같은 툴로 확인할 수 있어 민감한 데이터는 암호화해야 한다

 

요청 헤더의 Content-Type에 Body로 보낼 타입을 명시하는 것이 중요하다

 

 

Response 메시지

HTTP/1.1 200 OK → HTTP 버전이 1.1이며 상태코드 200(요청성공)이 OK라는 의미

데이터를 전송할 필요가 없을 경우 body가 비어있다

 

 

 


React에서 서버의 데이터를 받아오는 방법으로 보통 axios 라이브러리를 많이 사용하는데 우리는 자체로 fetch를 사용해서 HTTP 통신을 위한 HTTP 클라이언트를 구현하였다

API 보내고 받아올 때마다 사용하기 때문에 util 폴더에 따로 두었다


class WebServiceManager{
    #url;
    #method;
    #formDatas;
    #binaryDatas;
    #headerData;
    #credentials;
    #listener;


    constructor(url,method,listener) {
        this.#listener=listener;
        this.#url=url;
        this.#method=method;
        this.#formDatas={};
        this.#binaryDatas={};
        this.#headerData={};
        this.#credentials='omit'; 
    }

    addFormData(key,data) { //문자열 data
        this.#formDatas[key]=data;
    }

    addBinaryData(key,data) {
        this.#binaryDatas[key]=data;
    }

    addHeader(key,data) {
        this.#headerData[key]=data;
    }

    setCredentials(data) {
        this.#credentials=data;
    }

    async start() {
        var response;
        if(this.#method==='post' || this.#method==='POST') { //POST 방식일때
            let bodyData = new FormData();
            for(const [key,value] of Object.entries(this.#formDatas))
                bodyData.append(key,JSON.stringify(value));

            for(const [key,value] of Object.entries(this.#binaryDatas))
                bodyData.append(key,value);

            response = await fetch(this.#url,{method:this.#method,body:bodyData,headers:this.#headerData,credentials:this.#credentials})
            .catch(()=>{const listener = this.#listener.bind(); listener();});           
        }
        else { //GET방식일때
            response = await fetch(this.#url,{headers:this.#headerData,credentials:this.#credentials})
            .catch(()=>{const listener = this.#listener.bind(); listener();});            
        }
        
        if(response.ok)
            return response;
    }
}

export default WebServiceManager;

 

 

서버로 부터 데이터 받아오기 - 판매내역 (GET방식)

import WebServiceManager from "../../util/webservice_manager";
this.state = {
    goodsContents: [],
}
componentDidMount() {
    this.callGetGoodsAPI().then((response) => {
        this.setState({ goodsContents: response})
    });
}
async callGetGoodsAPI() {
    let manager = new WebServiceManager("http://.../wparts/GetGoods?login_id=1");
    let response = await manager.start();
    if (response.ok)
        return response.json();
}

1. WebServiceManager를 import시켜준다

2. 페이지 접근 초기에 데이터를 받아와야 하므로  componentDidMount에서 async 함수를 호출한다

3. 구현한 WebServiceManager를 이용해서 url과 method만 넘겨주면 response를 받아온다 (Get요청일때는 메서드는 생략하고 url만 보내준다)

4. 비동기 함수 callGetGoodsAPI()에서 response를 받아오면 setState를 해준다

 

 

 

이렇게 판매내역의 데이터를 받아온 것을 볼 수있다

 

 

 

 

 

 

서버로 부터 데이터 보내기 - 회원등록 (POST 방식)

import WebServiceManager from "../../util/webservice_manager";
this.state = {
    companyNo: '', //사업자등록 번호
    companyName: '', //회사상호명
    companyAddress: '', //사업자 주소
    passwd: '',     //비밀번호
    passwdOk: '', //비밀번호 확인
    companyNoImageURI: '', //사업자 등록증 사진
    nameCardImageURI: '', //명함 사진
}

 

*회원등록 버튼을 눌렀을 때 실행되는 함수

goAddUser = () => {
    this.callAddUserAPI().then((response) => {
        console.log('adduser', response);
        if (response.success === 0) {
            alert("이미 있는 사업자번호입니다");
        }
        else if (response.success === -1) {
            alert("서버 오류로 회원가입에 실패했습니다.");
        }
        else {
            alert('가입 신청 완료', '입력 된 내용 확인 후 승인이 완료됩니다.');
            this.props.hideButtonClicked()
        }
    })
}
//회원정보 서버에 등록 API
async callAddUserAPI() {
    const userData = {
        companyNo: this.state.companyNo.replace(/-/g, ''),
        companyName: this.state.companyName,
        companyAddress: this.state.companyAddress,
        passwd: this.state.passwd
    };

    let manager = new WebServiceManager("http://.../wparts/AddUser", "post");
    manager.addFormData("data", userData);
    manager.addBinaryData("file1", this.state.companyNoImageURI); //사업자 등록증 이미지
    manager.addBinaryData("file2", this.state.nameCardImageURI); //명함 이미지

    let response = await manager.start();
    if (response.ok) {
        return response.json();
    }
}

1. WebServiceManager를 import시켜준다

2. 회원등록 버튼을 눌렀을 때 데이터를 보내야 하므로 goAddUser()에서 async 함수를 호출한다

3. 구현한 WebServiceManager를 이용해서 url과 method를 전달한다

(post방식이므로 json일 경우는 addFormData(), 이미지일경우 addBinaryData()를 이용해서 각 데이터를 Body로 보내준다)

4. 비동기 함수 goAddUser()에서 response를 받아오면 각response.success에 해당하는 작업을 처리해준다

 

 

728x90
반응형
Comments