HTTP 통신 & Retrofit

박민균·2021년 6월 13일
0
post-thumbnail

HTTP

1. HTTP란?

HTTP(Hyper Text Transfer Protocol)는 Hyper Text 즉 HTML을 전송하기 위한 프로토콜, TCPUDP를 사용하여 통신하며 80번 포트를 사용하는 통신프로토콜(통신규약)이다.

  • Hyper Text란 text를 넘어서 링크, 이미지 등 다양한 것들에 대한 표현이다.
  • HTML이란 웹 문서의 뼈대를 구성하는 언어. 브라우저를 통해서 웹 문서를 읽을 수 있다.

❗️HTTP의 특징

  • HTTP 메세지는 서버클라이언트에 의해 해석된다.
  • TCP/IP를 이용하는 응용 프로토콜(Application Protocol)이다.
  • HTTP는 연결 상태를 유지하지 않는 비연결형 프로토콜이다. 즉, 클라이언트가 이전에 요청한 내용을 기억하고 있지 않는다.
  • 비연결성의 단점을 해결하기 위해 Cookie와 Session이 등장했다.
  • 비연결성 프로토콜이므로 요청/응답 방식으로 동작한다.
  • HTML 문서만이 HTTP 통신을 위한 문서가 아니다.
    - JSON 데이터 및 XML과 같은 형태의 정보도 주고 받을 수 있다.
    • 보통은 클라이언트가 어떤 정보를 어떤 형태로 받고 싶은지 명시하는 경우가 많다.
      즉, HTML로 받을지 JSON형태로 받을지 명시하는 것.

2. HTTP 통신(Request & Response)

  • 요청(Request)과 응답(Response)로 이루어져 있다.
  • 클라이언트가 서버에 요청을 보내고,
  • 서버는 요청에 대한 응답 결과를 준다.
  • 클라이언트 사용자에게 서버로 부터 응답받은 결과를 보여준다.

1) HTTP 요청(Request) 메시지

1. 요청 행(Request-Line)
Request-Line은 요청 방식(Method), URL정보, HTTP버전을 포함한다.
아래 그림에서는 Request URL, Request Method를 나타내고 있다.


2. 요청 헤더(Request Header)
헤더 정보는 요청하는 클라이언트 PC, 브라우저 정보, 사용자언어 환경, 쿠키 등 다양한
클라이언트 환경에 대한 정보를 가지고 있다.

3. 공백(CRLF)
줄 바꿈 명령.

4. 메시지 본문(Body)
Body, 클라이언트가 입력한 데이터를 저장하는 영역.
데이터 형식은 요청 헤더에 지정된 타입을 따른다.

2) HTTP 응답(Response) 메시지

1. 응답 행(State-Line)
응답 상태정보 표시 라인, HTTP버전 정보와 세 자리 값(200)과 같은 상태코드 값을 통해
응답 결과 및 상태정보를 나타낸다.

2. 응답 헤더 정보
헤더 정보, 각종 서버 및 웹사이트 관련 환경정보를 제공한다.

3. 메시지 본문(Body)
HTTP본문영역, 주로 서버에서 사용자에게 전달되는 HTML 소스 및 포함된 데이터를 저장하는 영역이다.

3. HTTP Method

HTTP Method는 송수신 방법을 뜻하며, GET, POST, PUT, DELETE, PATCH 등이 있다.
웹 페이지에서는 대부분 통신에 GET 메서드를 사용하며, 폼 등을 사용해서 데이터를 전송할 땐
POST 메서드를 사용한다.
즉, 클라이언트가 웹 서버에게 사용자의 요청의 목적/종류를 알리는 수단이다.

- GET(검색)
웹 서버에 페이지를 요청한다. 요청할 때 필요한 데이터는 URL에 덧붙여 보낸다.
- POST(생성)
서버의 데이터를 갱신하거나 보내는 데이터 양이 많을 때 등 사용한다.
요청할 때 필요한 데이터는 메시지 본문에 담아서 보낸다.
- PUT(변경)
대상 자원을 나타내는 데이터를 대체한다.
- DELETE(삭제)
웹 자원을 제거할 때 사용한다. 하지만 DELETE의 경우 서버에서 클라이언트의 요청을 무시 가능하기 때문에 실제로 삭제되지 않았지만, 클라이언트는 파일이 삭제 되었다고 생각할 수 있다.
- PATCH(일부 변경)
자원의 일부를 수정할 때 사용한다.

4. HTTP Status Code

  • 1xx : Informational : 요청 정보 처리 중
  • 2xx : Success : 요청을 정상적으로 처리함
  • 3xx : Redirection : 요청을 완료하기 위해 추가 동작 필요함
  • 4xx : Client Error : 서버가 요청을 이해하지 못함
  • 5xx : Server Error : 서버가 요청 처리 실패함

1xx : Informational 정보

서버가 요청을 클라이언트에서 성공적으로 수신했으며 서버 끝에서 처리 중이라는 정보를 나타낸다.

2xx : Success 성공

서버가 요청을 받고 성공적으로 처리되었음을 나타낸다.

  • 200 : GET 요청에 대한 성공
  • 204 : No Content. 성공했으나 응답 본문에 데이터가 없음
  • 205 : Reset Content. 성공했으나 클라이언트의 화면을 새로고침하도록 권고
  • 205 : Partial Content. 성공했으나 일부 범위의 데이터만 반환

3xx : Redirection 리다이렉션

300번대 상태 코드는 대부분 클라이언트가 이전 주소로 데이터를 요청하여 서버에서 새 URL로 리다이렉트를 유도하는 경우이다.

  • 301 : Moved Permanetly. 요청한 자원이 새 URL에 존재
  • 303 : See Other. 요청한 자원이 임시 주소에 존재
  • 304 : Not Modified. 요청한 자원이 변경되지 않았으므로 클라이언트에서 캐싱된 자원을 사용하도록 권고.

4xx : Client Error

400번대 상태 코드는 클라이언트의 코드가 잘못된 경우이다. 유효하지 않은 자원을 요청했거나 요청이나 권한이 잘못된 경우 발생한다.

  • 400 : Bad Request. 잘못된 요청
  • 401 : Unauthorized. 권한 없이 요청
  • 403 : Forbidden. 서버에서 해당 자원에 대한 접근 금지
  • 405 : Method Not Allowed. 허용되지 않은 요청 메서드
  • 409 : Conflict. 최신 자원이 아닌데 업데이트하는 경우

5xx : Server Error

500번대 상태 코드는 서버 쪽에서 오류가 난 경우이다.

  • 501 : Not Implemented. 요청한 동작에 대해 서버가 수행할 수 없는 경우
  • 503 : Service Unavailable. 서버가 과부하 또는 유지 보수로 내려간 경우.

Retrofit

1. Retrofit 이란?

안드로이드에서 서버와 클라이언트 간의 Http 통신을 도와주는 라이브러리입니다.
클라이언트에서 서버로 어떠한 요청을 보내면 서버는 그 요청에 대한 응답을 클라이언트로 보내주어야 하는데,
이 일련의 과정을 도와주는 역할을 하는 것이 Retrofit 입니다.

초기 안드로이드에서는 서버와의 통신을 위해 HttpClient를 사용했다. 그러나 HttpClien는 Android 5.1 이후로 deprecated 된 후, OKHttp와 그 상위 구현체인 Retrofit을 서버 통신을 위한 라이브러리로 사용된다.

  • REST API 통신을 위해 구현되었다.
  • OKHttp 라이브러리의 상위 구현체
  • retrofit은 OKHttp를 네트워크 계층으로 활용하고 그 위에 구축되었다.

1) Retrofit의 장점

  • 빠른 성능
    OKHttp는 AsyncTask를 사용(AsyncTask 보다 3~10배의 성능 차이가 있음)
  • 간단한 구현
    반복된 작업을 라이브러리에 넘겨서 처리하므로 간단한 구현이 가능하다.
  • 가독성
    Annotation(어노테이션) 사용으로 가독성이 뛰어남.
  • 동기/비동기 쉬운 구현
    - 동기 Synchronous - 동시에 일어난다는 의미로, 요청-응답이 하나의 트랜잭션에서 발생
    요청 후 응답까지 대기한다는 의미
    - 비동기 ASynchronous - 동시에 일어나지 않는다는 뜻, 요청-응답은 별개의 트랜잭션
    요청 후 응답이 도착하면 Callback으로 받아침.

2) Retrofit의 구성 요소

  • DTO(POJO)
    'Data Transfer Object', 'Plain Old Java Object' 형태의 모델
    JSON 타입변환에 사용
  • Interface
    사용할 HTTP CRUD동작(메소드) 들을 정의해놓은 인터페이스
    CRUD -> HTTP Method(POST, GET, PUT, DELETE)
  • Retrofit.Builder 클래스
    Interface를 사용할 인스턴스, baseUrl(URL) / Converter(변환기) 설정

2. Retrofit 사용법

Retrofit2를 이용하여 자신의 Github 정보를 불러오는 예제를 정리했습니다.

1. Retrofit 추가 & 권한 설정

1-1) build.gradle (Module: app)

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

1-2) AndroidManifest.xml에 인터넷 사용 권한추가

<uses-permission android:name="android.permission.INTERNET" />

2. DTO Class 생성

data class UserInfo(
    @SerializedName("login")
    val userId: String,
    val followers: Int,
    val following: Int
)

https://api.github.com/users/유저아이디

위에 주소로 접속하게 되면 아래와 같이 많은 유저 정보가 나오는데
그 중 유저 아이디, 팔로워 수, 팔로잉 수에 대한 정보만을 담는 DTO Class를 생성합니다.

변수의 이름을 JSON의 키 값과 이름을 맞춰 매핑하거나
@SerializedName을 통해 매핑시킬 수 있습니다.

3. API Interface 생성

interface Service {
    @GET("users/alsrbs12304")
    fun getUserInfo(): Call<UserInfo>
}

API Interface를 생성 후 어노테이션을 이용해 HTTP Method를 설정해 준다.
해당 유저의 정보를 검색하기 때문에 HTTP Method 중 GET메서드를 사용한다.

4. Retrofit Builder 생성

object RetrofitBuilder {
    var service : Service
    init {
        val retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        service = retrofit.create(Service::class.java)
    }
}

Retrofit Builder 를 object로 만들어 싱글톤으로 생성.
.baseUrl() 에는 서버의 주소를 넣는데 항상 주소 끝에는 '/'로 끝나야 한다.
.addConverterFactory()는 데이터를 파싱 할 converter를 추가하는 메서드이다.
JSON 같은 데이터는 자바나 코틀린에서 바로 사용할 수 있는 데이터 형식이 아니기 때문에 이를 변환해주기 위해 converter를 사용해야 한다.
여기서는 JSON을 변환해줄 GSON 변환기를 등록한 것이다.

이렇게 만들어진 Retrofit 객체를 이용해 Interface를 구현한다.

5. 요청과 응답

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        RetrofitBuilder.service.getUserInfo().enqueue(object : Callback<UserInfo> {
            override fun onResponse(call: Call<UserInfo>, response: Response<UserInfo>) {
                val userInfo = response.body()
                Log.d("response", "${userInfo?.userId} ${userInfo?.followers} ${userInfo?.following}")
            }
            override fun onFailure(call: Call<UserInfo>, t: Throwable) {
                Log.d("error", t.message.toString())
            }
        })
    }
}

enqueue로 비동기 통신을 실행한다. 통신종료 후 이벤트 처리를 위해 Callback 등록
onResponse -> 성공
하지만 onResponse가 무조건 성공을 뜻하는 것은 아니기 때문에 isSuccesful()로 확인이 필요하지만 생략했다.
onFailure -> 실패를 뜻함.

onResponse로 성공하면 응답에 대한 Body를 userInfo에 담아 로그로 확인한다.

0개의 댓글