이 포스팅은 <SNS 앱을 만들면서 배우는 안드로이드 클라이언트 개발>, 장성환, 비제이퍼블릭(2022)을 읽고 개인 학습용으로 정리한 글입니다.
스킴(scheme): 어떨게 자원을 가져올 지 알려줌(http, ftp, file)
아이디, 비밀번호
호스트(host): 서버의 연결을 구분하기 위해 사용하는 번호
-> 프로토콜마다 표준값 있음(HTTP 80, HTTPS 443)
-> 생략 가능
경로(path): 서버에서 리소스의 위치 가리킴(대소문자 구분)
질의(query): 서버에 추가로 전달되는 매개변수, 키-값 구조, &로 구분
프래그먼트(fragment): 리소스 내의 위치
HTTP 요청은 세 부분으로 구성됨
요청 줄(Request Line)
헤더(Headers)
본문(Body)
HTTP 응답도 요청과 마찬가지로 세 부분으로 구성
상태 줄(Status Line)
헤더
본문
GET
서버의 리소스 조회, 서버의 리소스 변경 x
ex. 파일 다운, 사용자 정보 조회
GET 요청은 쿼리를 통해 데이터 전달
-> URI는 길이 제한이 있으므로 주의 필요
일반적으로 GET 요청은 본문 X
-> API에서 GET 방식의 본문을 필요로 한다면 사용할 라이브러리에서 이를 지원하는지 확인 필요
POST
새로운 리소스 생성
ex. 회원가입, SNS에 새로운 글 작성
입력하는 폼(Form)이 있다면 일반적으로 POST로 요청
-> 입력한 데이터를 HTTP 메세지의 본문으로 전송
PUT
리소스를 생성하거나 리소스 전체를 교체
POST로 여러번 요청하는 경우: 새로운 리소스 계속 만들어짐
PUT으로 여러번 요청하는 경우: 최초엔 새로운 리소스 만들어짐, 이후엔 교체됨
보통 PUT 요청에는 리소스의 위치가 포함되어 있음
PATCH
DELETE
사용할 일이 적은 메서드들:
HEAD: GET과 동일하지만 응답에 본문 포함X
-> 헤더로 보내주는 정보 필요할 때 사용
OPTIONS: 서버/리소스에 사용할 수 있는 메서드 조회
TRACE: 보낸 요청을 그대로 돌려줌
CONNECT: 리소스 연결 요청
ex. 터널링에 사용
멱등성(Indempotent): 연산을 여러번 적용하더라도 결괏값이 달라지지 않는 성질
ex. 특정 리소스에 대해 DELETE 요청을 한번 한 것과 여러번 한 것: 서버 입장에선 결과 같음(멱등성 성립)
ex. 특정 리소스에 대해 POST 요청을 한번 한 것과 여러번 한 것: 매번 새로운 리소스 생성됨(멱등성 성립X)
멱등성이 성립한다는 것 =/= HTTP 응답이 같다는 것
Host: 요청하는 서버의 호스트 명, 포트
(기본 포트(HTTP 80, HTTPS 443)을 사용하는 경우 생략 가능)
Accept: 클라이언트가 응답으로 받기를 원하는 컨텐츠 타입과 우선순위
User-Agent:요청하는 프로그램/프로그램이 실행 중인 환경에 대한 정보
Referer: 요청을 보낸 페이지의 주소
ex. A 페이지에서 링크를 클릭해 B 페이지로 이동한 경우: B 페이지를 요청할 때 Referer 헤더로 A 전달
If-Modified-Since: 서버의 리소스가 특정 시간 이후 변경된 경우에만 Entity 보내달라 요청
-> Entity 생략되었을 때: 클라이언트의 캐시 사용
⚡If-None-Match: 서버 리소스의 Etag가 다른 경우 요청 처리
ex. 요청에 포함되는 Etag과 서버의 Etag 일치하지 않는 경우 PUT 요청은 리소스 변경, GET 요청은 Entity를 포함한 응답 내려줌
Server: 요청을 처리한 서버의 프로그램 정보
Location: 클라이언트가 요청한 리소스의 실제 위치
ex. 클라이언트의 요청으로 리소스가 새로 생성됐을 때 클라이언트에게 이 주소를 알림
ex. 리소스의 위치가 변경돼 클라이언트를 이동시키기 위해 사용
Etag: Entity 태그, 리소스의 특정 버전을 식별
ex. 클라이언트는 응답으로 받은 Etag 값을 조건부 요청 헤더(If-Match, If-None-Match)로 전달해 사용
Last-Modified: 리소스의 마지막 수정 시간
-> 클라이언트는 응답으로 받은 Last-Modified 값을 조건부 요청 헤더(If-Modified-Since, If-Unnmodified-Since)로 전달해 사용
Date: HTTP 메세지가 만들어진 시간
Coonection: 네트워크 연결 재사용을 위해 유지 여부 제어
-> close면 연결 끊기, keep-alive면 유지
(HTTP/2에서는 항상 연결 유지 -> 사용 금지)
CacheControl: 서버와 클라이언트, 프록시 사이의 캐시 정책 제어
-> 전송된 리소스가 유효하다고 판단되는 시간 max-age 지시자로 전달
-> 응답 공유될 수 있는지 public, private 지시자로 전달
Content-Type: 본문의 콘텐츠 타입과 문자 인코딩 정보
Content-Length: 본문의 길이, 이 길이 정보를 통해 모든 데이터 받았는지 확인 가능
-> 데이터 크거나 동적으로 생성해 Chunk로 나눠 보내는 경우: Tranfer-Encoding 헤더를 chunked로하고 Content-Type 헤더 생략
Content-Encoding: 본문 압축에 대한 정보
-> 본문 압축하여 전송: 전송 속도와 대역폭에서는 이득, 서버와 클라이언트 성능에서는 손해
100 Continue: 요청의 일부를 받았고 나머지를 이어서 올리길 기다립니다
101 Switching Protocols: 클라이언트의 요청으로 프로토콜을 변경합니다
-> Websocket을 사용할 때 많이 사용됨
200 OK: 요청 성공적으로 수행됨
(의미 포괄적 -> 201, 202, 204등 구체적인 코드가 있는 경우에도 200을 내리는 경우 많음)
201 Created: 요청이 성공적으로 수행되어 리소스가 만들어졌습니다
202 Accepted: 서버가 요청을 접수했지만 아직 처리되지는 않았습니다
204 No Content: 요청을 처리했지만 콘텐츠는 없습니다
(ex. DELETE 요청을 수행한 결과, 콘텐츠 수정을 요청했지만 변경된 것이 없는 경우)
303 Moved Permanently: 요청한 리소스가 응답의 Location 헤더의 위치로 옮겨졌습니다
-> 리소스가 영구적으로 옮겨졌을 때 사용
(ex. 사이트를 옮겼거나 여러 도메인을 사용할 때)
302 Found: 요청한 리소스가 응답의 Location 헤더의 위치로 옮겨졌습니다
-> 일시적으로 옮겨져 향후 원래 주소로 요청해야할 때 사용
304 Not Modified: 요청한 리소스가 변경되지 않아 재전송을 할 필요가 없습니다
-> 이미 클라이언트가 요청한 리소스를 가지고 있어, 데이터를 다시 받을 필요 없을 경우 사용
400 Bad Request: 클라이언트의 요청이 잘못됐습니다
(ex. 요청에 포함되는 정보 생략되었을 때, 잘못된 형식일 때)
401 Unauthorized: 인증이 필요한 리소스를 요청했지만 요청에 인증이 없습니다
(ex. 로그인이 필요한 API를 호출했을 때)
403 Forbidden: 권한이 없어서 요청이 거부되었습니다
(ex. 관리자 권한이 필요한 기능을 일반 사용자가 호출한 경우, 본인만 변경할 수 있는 API를 다른 사람이 호출하는 경우)
404 Not Found: 요청한 리소스가 없습니다, 존재하지 않는 리소스를 요청했습니다
409 Conflict: 요청이 서버 상태와 충돌했습니다
(ex. 이미 사용 중인 아이디로 가입하려는 경우, 친구 신청을 보냈는데 이미 친구인 경우)
500 Internal Server Error: 서버에서 오류가 발생해 요청을 처리할 수 없습니다
-> 서버의 스크립트, 데이터베이스 등 여러 구성 요소 중 하나에서 발생한 오류
-> 오류에 대한 상세 정보를 본문으로 함께 전달하기도 함
503 Service Unavailable: 서비스를 사용할 수 없습니다
(ex. 서비스 점검 중, 너무 많은 요청으로 과부하 상태)
머티리얼 디자인은 8dp 그리드에 맞춰 구성 요소 배치 권장
Material로 시작하는 뷰: 머티리얼 디자인을 위한 기능들이 추가된 뷰
LinearLayout의 showDividers
TextAppearance
TextView의 경우
-> 모든 뷰에서 사용할 수 있는 style 속성을 통해서는 위젯의 컬러나 크기 설정
-> textAppearance 속성으로 텍스트의 크기, 폰트 패밀리 등 지정
머티리얼 디자인에는 용도에 따라 사용할 수 있는 다양한 텍스트 스타일 준비됨
ex. @style/TextAppearance.MaterialComponents.Headline6
안드로이드 앱을 네트워크에 연결
-> 매니페스트에 android.permission.INTERNET권한 추가
안드로이드 9(API28)부터 보안을 강화하기 위해 암호화되지 않은 HTTP 프로토콜 사용 제한됨
-> 매니페스트의 application에 android:usesCleartextTraffic="true" 추가
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Thread{
val url = URL("http://10.0.2.2:5000/v1/hello-world")
val conn = url.openConnection() as HttpURLConnection
conn.connectTimeout = 5000
conn.readTimeout = 5000
conn.requestMethod = "GET"
conn.connect()
val reader = BufferedReader(InputStreamReader(conn.inputStream))
val body = reader.readText()
reader.close()
conn.disconnect()
activity?.runOnUiThread {
binding.question.text = body
}
}.start()
}
방법 1
- View 사이사이에 seperator 역할을 하는 view들을 직접 삽입
<View android:layout_width="match_parent" android:layout_height="1px" android:layout_marginTop="5dp" android:layout_marginBottom="5dp"/>
⭐방법 2
- LinearLayout의 showDividers 속성을 true로 한다
- API 11 이상에서만 가능
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@drawable/separator" android:showDividers="middle" android:orientation="vertical"> ... </LinearLayout>
⚡방법 3
- ButtonBarStyle 사용
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" style="?android:buttonBarStyle" android:orientation="vertical"> ... </LinearLayout>
안녕하세요 저자입니다. 검색해보다가 우연히 발견했습니다. 책의 내용에 이상한 부분이 있으면 카페로 문의주세요! https://cafe.naver.com/androidclientdev