요청 생명주기
Flask 애플리케이션은 클라이언트 요청이 들어오면 WSGI 서버를 거쳐 전역 훅, 라우팅, 뷰 함수를 실행하고 다시 역순으로 응답을 반환하는 구조를 갖는다.
요청 객체 (Request)
Flask의 request 객체는 현재 요청에 대한 모든 정보를 담고 있다. from flask import request로 가져올 수 있으며, 내부적으로 Werkzeug의 Request 클래스를 기반으로 한다. 주요 속성은 다음과 같다.
| 속성 | 설명 | 타입 |
|---|---|---|
data | 요청 본문을 바이트 문자열로 제공. Form, JSON 등으로 해석되지 않는 원시 데이터를 담음 | bytes |
form | HTML 폼 데이터 | ImmutableMultiDict |
args | 쿼리 문자열 파라미터 | ImmutableMultiDict |
cookies | 클라이언트가 보낸 쿠키 | Dict |
headers | 요청 헤더 | ImmutableMultiDict |
method | HTTP 메서드 (GET, POST 등) | str |
url | 요청 URL 전체 | str |
files | 업로드된 파일 목록 | ImmutableMultiDict |
json | JSON 형식의 요청 본문 | dict |
요청 데이터 추출
다음 예제는 다양한 요청 데이터를 읽는 방법을 보여준다. GET과 DELETE는 본문이 없으므로 POST, PUT, PATCH만 허용했다.
from flask import Flask, request
from pathlib import Path
app = Flask(__name__)
app.config['DEBUG'] = True
@app.route('/api/data', methods=['POST', 'PUT', 'PATCH'])
def handle_data():
# 원시 본문 (XML, 바이너리 등)
raw_body = request.data
# 폼 데이터
user_name = request.form.get('name')
user_age = request.form.get('age')
# JSON 요청
if request.is_json:
payload = request.json
username = payload.get('username')
# 파일 업로드 (multipart/form-data)
uploaded = request.files.get('avatar')
if uploaded:
save_path = Path(__file__).parent / 'uploads' / uploaded.filename
uploaded.save(save_path)
# 헤더 정보
host = request.headers.get('Host')
custom_token = request.headers.get('X-Auth-Token')
# 클라이언트 정보
user_agent = request.user_agent
remote_ip = request.remote_addr
server_info = request.server
# 요청 메서드와 URL
method = request.method
full_url = request.url
url_path = request.path
return '데이터 처리 완료'
응답 생성
Flask는 HTML, JSON, 리다이렉트 등 다양한 응답을 지원한다. 뷰 함수가 문자열을 반환하면 Flask가 자동으로 Response 객체로 변환한다.
HTML 응답
from flask import Flask, make_response, Response
app = Flask(__name__)
@app.route('/')
def home():
# 기본 HTML 반환
return '<h1>환영합니다</h1>', 200, {'X-Custom-Header': 'flask'}
@app.route('/explicit')
def explicit():
resp = make_response('<p>명시적 응답</p>', 201)
resp.headers['X-Info'] = 'custom'
return resp
JSON 응답
jsonify()를 사용하면 리스트, 딕셔너리 등 복합 데이터를 JSON으로 직렬화할 수 있다. Decimal 같은 타입도 자동 처리된다.
from flask import Flask, jsonify
from decimal import Decimal
app = Flask(__name__)
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
@app.route('/api/users')
def get_users():
users = [
{'id': 1, 'name': 'alice', 'score': Decimal('98.5')},
{'id': 2, 'name': 'bob', 'score': Decimal('87.2')}
]
return jsonify(users)
리다이렉트
리다이렉트는 redirect() 함수로 간편하게 처리할 수 있다. 내부적으로 Location 헤더와 상태 코드를 설정한 Response를 반환한다.
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/old')
def old_page():
# 외부 사이트로 영구 이동 (301)
return redirect('https://example.com', 301)
@app.route('/profile')
def profile():
return '프로필 페이지'
@app.route('/login')
def login():
# 내부 엔드포인트로 임시 이동 (302)
return redirect(url_for('profile'))
@app.route('/item/')
def item_detail(item_id):
return f'아이템 {item_id}'
@app.route('/goto-item')
def goto_item():
# 동적 URL 생성 후 리다이렉트
target_url = url_for('item_detail', item_id=42)
return redirect(target_url)
사용자 정의 상태 코드와 헤더
@app.route('/custom')
def custom_response():
body = '생성됨'
status = 201
headers = {'X-API-Version': '1.2'}
return body, status, headers
HTTP 세션 제어
HTTP는 무상태 프로토콜이므로 사용자 상태를 유지하기 위해 쿠키와 세션을 사용한다.
쿠키 (Cookie)
쿠키는 서버가 생성하여 클라이언트에 저장하는 작은 텍스트 데이터다. response.set_cookie()로 설정하며, max_age를 지정하지 않으면 세션 쿠키(브라우저 종료 시 삭제)가 된다.
from flask import Flask, request, make_response
app = Flask(__name__)
@app.route('/cookie/set')
def set_cookie():
resp = make_response('쿠키 설정')
resp.set_cookie('user_id', 'abc123', max_age=3600) # 1시간 유효
resp.set_cookie('theme', 'dark') # 세션 쿠키
return resp
@app.route('/cookie/get')
def get_cookie():
uid = request.cookies.get('user_id')
theme = request.cookies.get('theme', 'light')
return f'사용자: {uid}, 테마: {theme}'
@app.route('/cookie/delete')
def delete_cookie():
resp = make_response('쿠키 삭제')
resp.set_cookie('user_id', '', max_age=0)
resp.set_cookie('theme', '', max_age=0)
return resp
세션 (Session)
Flask의 세션은 기본적으로 클라이언트 쿠키에 암호화되어 저장된다. SECRET_KEY 설정이 필수이며, session 객체를 통해 딕셔너리처럼 사용한다.
from flask import Flask, session
app = Flask(__name__)
app.secret_key = 'your-secret-key-here'
@app.route('/session/set')
def set_session():
session['username'] = 'alice'
session['cart'] = ['item1', 'item2']
return '세션 저장됨'
@app.route('/session/get')
def get_session():
user = session.get('username', 'guest')
cart = session.get('cart', [])
return f'{user}님의 장바구니: {cart}'
@app.route('/session/delete')
def delete_session():
session.pop('username', None)
session.pop('cart', None)
return '세션 삭제됨'
세션 데이터는 쿠키에 저장되므로 쿠키가 클라이언트에서 삭제되면 세션도 사용할 수 없다. 대규모 서비스에서는 Flask-Session 확장을 통해 Redis나 데이터베이스에 저장하는 것이 일반적이다.