Computer/Server

Python으로 웹 서버 제작 - HTTP 헤더

kentakang 2018. 9. 6. 04:32
반응형

Python으로 웹 서버 제작 - HTTP 헤더


안녕하세요, kentakang 입니다.

지금 학교에서 소켓 통신에 대해 배우고 있는데, 저번에는 프로토콜을 제작했었습니다.

이번에는 다른 프로토콜을 이해하고, 공부하기 위해 HTTP 프로토콜을 지원하는 웹 서버를 만들어 보려 합니다.

이번 게시글에서는 상황에 맞는 HTTP 헤더를 반환하는 것을 해보려고 합니다.

우선 기본적인 소켓 통신의 예제입니다.


Github


파이썬의 socket을 통해 localhost:12345를 통해 요청을 받고,

받은 데이터를 그대로 다시 클라이언트에게 송신하는 예제입니다.

이걸 응용해서 요청을 받고, HTTP 프로토콜 규격에 맞게 다시 전송해주는 서버를 만들어보겠습니다.

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(('localhost', 12345))
server_socket.listen(0)

client_socket, addr = server_socket.accept()
data = client_socket.recv(65535)

print(data.decode())


저는 일단 이런식으로 코드를 짜봤습니다.

이제 Insomnia라는 REST 통신 Client를 통해 요청을 전송하겠습니다.

웹 브라우저로 해당 주소에 접속하셔도 같은 결과를 얻을 수 있습니다.

클라이언트 상에서는 리턴된 값이 없다고 나옵니다.

저희가 아직 클라이언트에 전송한 값이 없기 때문에, 정상적인 결과입니다.

서버를 한번 확인해볼까요?

클라이언트에서 요청한 값을 확인해볼 수 있네요.

이를 통해 HTTP 프로토콜의 기본적인 구조를 알아볼 수 있습니다.

가장 처음에 오는 문자열은 Request Method 입니다.

웹 개발을 해보셨다면 GET, POST등의 메소드는 익숙하실탠데

GET, POST 이외에도 PUT, DELETE 등의 많은 메소드가 있습니다.

일단 저희는 GET 요청만 처리하는 서버를 만들어 보겠습니다.

우선 HTTP 요청 구조에 대해 분석해보겠습니다.

HTTP 요청은

GET / HTTP/1.1

Host: localhost:12345

User-Agent: insomnia/6.0.2

Accept: */*


과 같은 식으로 들어왔는데요.

가장 첫번째 줄의 GET은 Request Method 입니다.

그 다음 / 은 요청한 주소가 되겠네요. 만약 제가 localhost:12345/index.html 로 접속했다면, /index.html 이라고 표시됩니다.

그 다음 HTTP/1.1 은 HTTP 프로토콜의 버전입니다.

우리나라 사이트의 다수는 HTTP/1.1 버전을 사용하지만, HTTP/2를 사용하는 사이트도 다수 있습니다.

파라미터 별로 공백으로 구분이 되어 있으니, Python의 split을 이용해 request_method를 가져와 보겠습니다.

저는 이렇게 코드를 작성했습니다.

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(('localhost', 12345))
server_socket.listen(0)

client_socket, addr = server_socket.accept()
data = client_socket.recv(65535)

request_data = data.decode().split()
request_method = request_data[0]

print(request_method)

구동해보시면 GET이라고 Request Method가 나타나는 것을 알 수 있습니다.

이제 사용자에게 어떻게 응답할지를 구성해야겠죠?

우선 GET 메소드가 아닐 경우 잘못된 메소드라고 리턴하는 코드를 작성하겠습니다.

그 전에, HTTP의 응답 형식을 알아보겠습니다.

HTTP의 응답 형식은

HTTP/1.1 (HTTP 버전) 200 (HTTP 응답 코드) OK

헤더


HTML


이런 방식입니다.

전체적인 응답 형식은 알겠는데, 헤더에 어떤 정보가 들어가야 하는지 잘 모르겠네요.

네이버에 요청을 해서 어떤 식으로 응답이 오는지 보겠습니다.

이런식으로 응답이 오는 걸 확인할 수 있습니다.

네이버의 헤더에는 Server, Date, Content-Type 등등의 정보가 들어가 있는데요.

저는 일단 Server와 Date만 쓰도록 하겠습니다.

Server에는 서버 프로그램의 이름이 들어가고, Date에는 응답 당시의 시간 정보가 들어가네요.

import socket
from datetime import datetime

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(('localhost', 12345))
server_socket.listen(0)

client_socket, addr = server_socket.accept()
data = client_socket.recv(65535)

request_data = data.decode().split()
request_method = request_data[0]
request_version = request_data[2]

server_name = "Python Light-Weight Server"

if request_method == "GET":
response_data = "{0} 200 OK\nServer: {1}\nDate: {2}\n".format(request_version, server_name,
datetime.now().strftime('%a, %d %b %Y %H:%M:%S KST'))
else:
response_data = "{0} 405 Method Not Allowed\nServer: {1}\nDate: {2}\n".format(request_version, server_name,
datetime.now().strftime('%a, %d %b %Y %H:%M:%S KST'))


client_socket.send(response_data.encode())


저는 이렇게 코드를 작성했습니다.

여기서 404 Method Not Allowed는 지원하지 않는 Method 일때의 응답 코드입니다.

제대로 응답하는지 확인해볼까요?

우선 GET 요청입니다.

제대로 200 OK를 반환하고, 헤더의 내용도 잘 도착한 걸 볼 수 있네요.

이제 POST 요청을 해보겠습니다.

네 저희가 헤더에 담은 그대로 도착한 걸 볼 수 있습니다.

응답 코드는 405 Method Not Allowed에 Server와 Date 헤더도 정상적으로 도착했네요.

다음 게시글에서는 직접 HTML을 실어서 웹 서버의 기능을 구현해보도록 하겠습니다.

읽어주셔서 감사합니다.

반응형