Study/CSSU

[CSSU] HTTP request Methods

MuviSsum 2021. 4. 7. 22:06

 

첫 번째 주제 - HTTP request Methods

 

이제부터는 좀 더 깊이 있게 배워보려고 한다.

뭔가.. 수박 겉핥기식으로 배우니까 지식이 오래가지 않는 것 같아서 ㅠㅠ

 

처음엔 HTTP Methods를 알아본다! 저번에 GET과 POST에 대해서 알아봤는데,

블로그 정리로 알아봤다. 하지만 역시..... 제대로 공부하려면 공식문서가 답이다.

 

1. GET

진짜 밑의 표를 보고 공부하니까 정말 정확하게 이해하게 되는 것 같아서 기분 좋았다.

 

<GET Summary>

 

(1) GET은 본문을 포함해서 Request 하지 않는다.

요청할 때를 생각해보면 쉽다. URL 요청과 헤더만 주로 보내기 때문이다. 이건 정해진 거라서 뭘 설명하기도 그렇다.

그런데!! 이상한 짓을 해본 사람이 있다.

libsora.so/posts/http-get-request-with-body-and-http-library/

 

HTTP GET 요청에 body를 붙여서 보내면 어떤 일이 벌어질까? · /usr/lib/libsora.so

삽질의 시작 요새 유니티로 게임을 만들고 있다. 나는 서버쪽을 작업하고 있다. 서버는 HTTP 기반으로 구현하고 있다. 실시간 통신이 필요없으면 HTTP 쓰는게 편하잖아? RESTful API 같은 통신 규격으

libsora.so

해당 내용을 보니까, 일단 되는 라이브러리도 있고 아닌 것들도 있다.

그러니까 굳이 만들어야 한다면, POST를 좀 설정하는 방식으로 가는게 맞지 않나 싶다.

GET이 만들어진 이유를 알고 그 이유를 따라가자!

 

(2) Response 에는 본문이 있다.

GET은 데이터를 가져오기 위한 Method이다. 그러므로 데이터를 가져오기 위한 응답에는 본문이 있어야 한다.

밑은 데이터를 불러오는 예시이다.

ex) Vuejs - Django

ex) Vuejs - Spring

 

(3) 서버는 안전하게 유지된다.

Safe는 서버가 얼마나 안전하냐는 뜻이다. GET으로는 데이터를 가져오기만 하기 때문에 서버의 데이터를 가져올 뿐 서버의 데이터를 변경하지 않는다. 하지만 서버 설계가 잘 못 되어있는 경우는 큰 참사가 일어날 수도... (구글 엑셀레이터 사건처럼)

이 안전하다는 것을 착각하는 경우가 있다. 서버가 변하지 않는다는 뜻이지 중간에서 해킹을 못 한다는 뜻이 아니다. GET이든 POST든 다 해킹 가능하다. POST라고 BODY에 담아서 와서 보안이 튼튼하다? 는 아니라고 한다.

자 밑의 GET 형식과 POST 형식의 요청을 비교해 보자.

GET은 url로 page=123을 보내지만 POST는 본문에 page=123을 보낸다.

그냥 그 차이일 뿐이다. 암호화는 전혀되지 않는다. 그러므로 SSL을 쓰고 암호화를 하고 데이터를 보내는 것이다.

위의 사진은 밑의 스택오버플로우 게시물에서 가져왔다.

stackoverflow.com/questions/1008668/how-secure-is-a-http-post

 

How secure is a HTTP POST?

Is a POST secure enough to send login credentials over? Or is an SSL connection a must?

stackoverflow.com

 

(4) 멱등성을 가진다.

Imdepotent란 멱등성을 말한다. 여러 번 요청을 했을 때 똑같은 응답을 한다면 멱등성을 띄게 된다. 즉, 우리가 GET을 요청할 때 DB에 있는 데이터를 요청한다. 하지만 똑같은 주소로 똑같이 요청했다면 똑같은 응답을 가져올 것이다. 그럼 여기서 의문을 가질 수 있다.

"내가 요청한 후에 데이터가 추가되었으면 어떻게 해요?"

어떤 테이블의 전체 데이터를 가져오는 GET API인데 다른 POST 요청으로 데이터가 추가되었다. 다음 GET 요청에는 데이터가 당연히 추가되겠지만 이 멱등성은 똑같은 응답이 온다는 것은 서버상태가 변화되지 않았을 때이다. GET은 서버의 데이터가 추가된 후에, 추가된 데이터에 대해서 같은 응답을 한다.

즉, 멱등성이란 서버 상태를 변화시키지 않았을 때, 같은 응답을 하는 것을 말한다.

 

(5) 캐시할 수 있다.

GET Method는 받은 데이터를 캐시한다. 왜냐면 멱등성을 가지고 있을 뿐만 아니라, 데이터가 변하지 않았다면 굳이 서버에서 모든 데이터를 받아올 필요가 없기 때문이다. 그래서 데이터가 변했는지 확인을 거쳐 데이터가 변하지 않았다면 캐시된 데이터를 쓴다.캐시에 대한 내용은 서버 측과 클라이언트 측에서 설정할 수 있는데 'cache-control'이라는 변수를 통해 지정할 수 있다.

<클라이언트에서 쓰는 cache-control>
<서버에서 쓰는 cache-control>

 

'cache-control'에는 확장 명령어가 더 있다. 밑의 사이트를 들어가면 공식 문서를 볼 수 있다.

 

Cache-Control - HTTP | MDN

Cache-ControlCaching directives have the following rules to be valid: Case-insensitive, but lowercase is recommended. Multiple directives are comma-separated. Some directives have an optional argument, which can be either a token or a quoted-string. (See s

developer.mozilla.org

 

(6) HTML Form으로 사용가능하다.

우리가 폼으로 데이터를 보낼때 밑과 같이 보낼 수 있기 때문에 사용가능하다. HTML의 특성이라서 이건 HTTP Method 관점에서 더 설명할 수 있는게 없다.

ex) HTML form code (using GET method)

 

2. POST

<POST Summary>

 

(1) POST는 본문을 포함해서 Request 한다.

 POST의 목적을 생각해보면 이해가 빠르다. 우리는 데이터를 보내서 서버 내에 생성을 시켜야 한다. GET 같은 경우 데이터를 URL에 함께 보내게 되고 실제 API 사용자가 쉽게 볼 수 있으며, 데이터 길이의 제한이 있다. 하지만 Body라는 것을 따로 보내면 Body로 데이터가 들어가서 서버가 받기 때문에 데이터 길이 제한없이 보낼 수 있게 된다. 하지만 Body로 들어간다고 안전하게 전송 중 모든 사람이 못 보는 것은 아니다. 따라서 보안를 강화하기 위해 우리는 SSL을 필수로 사용한다.

※ 주의 점: 데이터 길이 제한이 없다고 하더라도 Web Server 상에서 제한을 걸 수 있다. 따라서 그 제한을 맞춰야 한다. 예를 들어, 우리가 머신러닝을 하며 나온 데이터를 DB로 저장한다고 하자. 그 데이터가 1M가 넘는데 제한이 1M이다. 그러면 한 번에 다 못보낸다. 따라서 Nginx 같은 경우 제한을 풀 수 있는데 밑과 같이 풀 수 있다.

<Nginx 설정>

 

(2) Response 에 본문이 있다.

 Response에도 본문이 존재한다. 이 말은 데이터를 불러온다는 뜻이다. 난 사실 이 부분이 이해가 조금 안 되었다. 데이터를 POST로 저장한다고 생각했을 때 생각한 것은...

"굳이 응답을 해야할까? 저장되었다고 201코드만 보내주면 되는 것 아닌가?"

그래서 찾아봤다.

FastAPI의 튜토리얼 코드이다.

@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

fastapi.tiangolo.com/tutorial/security/oauth2-jwt/?h=jwt

 

OAuth2 with Password (and hashing), Bearer with JWT tokens - FastAPI

OAuth2 with Password (and hashing), Bearer with JWT tokens Now that we have all the security flow, let's make the application actually secure, using JWT tokens and secure password hashing. This code is something you can actually use in your application, sa

fastapi.tiangolo.com

 보면은 POST로 보내는데도 jwt 세션을 생성하면서 access_token을 반환한다. 이걸 보고 느낀 것은 내가 너무 어렵게 생각했다는 점이다. POST 자체는 데이터를 생성한다는 것에 너무 집중한 나머지 다른 부분을 생각하지 못 했다. 응답코드만 있으면 된다라고 생각했던 나 자신이 좀 부끄러웠다. 데이터를 생성했다고 하더라도 어떤 부분에서 값을 다시 받는 데이터가 생길 수 있다. jwt 세션을 생성하고 access_token을 받는 것 처럼...!!

 

(3) 서버는 안전하지 않다.

POST 자체가 서버의 데이터에 추가하는 형식이다. 이는 서버에 새로운 데이터가 생성된다는 말이고 서버의 데이터가 바뀐다는 것을 의미한다. 따라서 서버는 안전하지 않다.

 

(4) 멱등성을 가지지 않는다.

 위에서 설명했듯이 멱등성은 멱등성이란 서버 상태를 변화시키지 않았을 때, 같은 응답을 하는 것을 말한다.

 POST는 데이터를 생성시키면서, 응답도 데이터 생성마다 다르다. 따라서 멱등성을 찾아 볼 수가 없다.

"근데, 서버가 꺼진 상태에서 POST를 여러번 요청하면 500에러가 나고 그러면 멱등성아닌가..?"

라는 어이없는 상상을 해보긴 했는데, 여기까지 하겠다. 개소린듯하니깐^^

 

(5) 일부 경우, 캐시 가능하다.

"Only if freshness information is included" 라고 한다. 이게 진짜 새로운 정보를 포함하는 응답이 있을 때만 가능한 줄 알았다. 하지만!!

보니까 Content-Location을 set 해주면 캐시가 된다고 한다. 근데 새 정보가 없는데 또 캐시할 필요는 없어 보인다.

 

(6) HTML Form으로 사용가능하다.

GET과 같다... ㅎ 그냥 쓸 수 있다. 이건 HTML에서 지원을 해주는 거니까!

 

3. PUT

※주의바람※ PUT은 POST와 겹치는 경우가 많아 설명을 조금 생략했다. ※주의바람※

 

(1) PUT은 본문을 포함해서 Request 한다.

이건 포스트와 비슷한 개념으로 생각하면 된다. POST로 보내던 것을 일부만 PUT으로 보내는 것이다. POST의 데이터 중 일부가 어떤 데이터가 될지 모른다. 그러므로 본문을 포함해서 보내야 데이터 길이 걱정이 없다.

 

(2) Response에 본문이 없다.

이거야 말로 앞에서 생각했던 post의 의문점이다. 일부를 변경한다는 것은 이미 데이터를 알고 있었다는 뜻이고, 새로 생성하는게 아니라 수정이다. 그러므로 응답할 것은 코드로 성공과 실패를 알려주면 된다. 즉, 본문이 필요없다.

 

(3) 서버는 안전하지 않다.

 앞에서 말한대로 안전하다는 것은 서버의 데이터가 변하지 않아야 한다. 서버 데이터를 수정하므로 안전하지 않다.

 

(4) 멱등성을 가진다.

이거 공부하면서 애매했다. POST는 멱등성을 안 가지고, GET은 가지잖아. 왜 PUT은 또 가지는거지? 개판이넹

하지만!! 역시 공식문서는 배반하지 않는다.

PUT으로 본문을 넣어서 똑같은 요청을 해보자. 그러면 데이터 수정이 같은 데이터에만 반복되므로 서버상태가 바뀌지 않으면서 응답이 같다. 하지만, POST로 본문을 넣어서 똑같은 요청을 해보자. 그러면 서버의 데이터에 데이터가 1, 2, 3, 4씩 쌓이게 된다. 내용은 같으면서 pk(autoincrease 설정)값은 다른 그런 데이터가 말이다. 그러므로 PUT은 POST와 다르게 멱등성을 가지게 된다.

 

(5) 캐시 불가능하다.

심지어 응답에 본문도 없는데, 캐시를 하려고 한다? 말이 안된다.

 

(6) HTML Form으로 사용 불가능하다.

지원 안해 주나보다. 그래도 한 번 더 찾아본다. 궁금하니까.

스택오버플로우 신님께서 말씀해주셨다. only support GET and POST!!! 알아듣고 갑니다 행님.

 

4. DELETE

 

(1~2) DELETE은 본문을 포함해서 Request 할 수도 Response 할 수도 있다.

이건 묶어서 설명해야 한다. 원래는 DELETE는 둘 다 지원하지 않는다.

하지만 지원해야 할 경우가 몇 가지 있는데, pk 값이 너무 큰 경우나 url에 넣을만한 요소가 아니거나. 이런 경우 get처럼 못 보낸다. 그래서 이렇게 body가 생기는 것이고, 이 값을 쓰려면 POST나 PUT과 다른 방식으로 보내거나, 프레임워크마다 요구하는 것이 좀 다르다.

제일 자주 쓰는 방식은 헤더에 넣어서 보내는 거나 원래 부터 body를 지원하는 형식 두 가진 것 같다. 프레임워크 별로 다르니까 delete쓸 때, body가 꼭 필요하다면, 각 프레임워크에 맞게 검색해서 찾아 쓰자! ㅎㅎ

 

(3) 서버는 안전하지 않다.

 앞에서 말한대로 안전하다는 것은 서버의 데이터가 변하지 않아야 한다. 서버 데이터를 삭제하므로 안전하지 않다.

 

(4) 멱등성을 가진다.

요고도 애매할 수 있다. 하지만 PUT과 같은 개념이다.

DELETE로 똑같은 요청을 해보자. 그러면 데이터 삭제가 같은 데이터에만 반복되므로 삭제가 되었으면 삭제, 삭제가 이미 되었으면 이미 되었다고 응답한다. 이렇게 한 데이터에만 주구장창 요청하니까 멱등성을 가진다.

그리고 주의해야할 점!!

위의 내용을 보면 DELETE 메소드로 데이터의 마지막 엔트리를 삭제하는 API를 만들지 마라고 되어있다. 이럴 경우 멱등성을 위반하기 때문이다.

 

(5) 캐시 불가능하다.

심지어 응답에 본문이 있다하더라도.. 삭제하고 나서 받은 데이터를 캐시할 이유가 없다^^ 진짜 필요하면 생기지 않을까? 아마도 라이브러리 몇 개정도는 있긴 할 것 같다.

 

(6) HTML Form으로 사용 불가능하다.

PUT에서 말했다.

only support GET and POST!!

 

할 일이 많아서 2주에 걸쳐서 다 쓰게 되었는데, 역시 뭔가 깊게 공부하니까 개념이 확실히 잡히는 것 같다. 오래도록 기억에 남기를 소망하며 다음 주에도 하나 정해서 써야겠다. 아마 JWT가 되지 않을까 싶다.

반응형

'Study > CSSU' 카테고리의 다른 글

[CSSU] 장고 튜토리얼  (0) 2021.08.22
[CSSU] SQL 정리  (0) 2021.06.25
[CSSU] JWT(JSON Web Token)  (0) 2021.05.07