from mod_python import apachedef requesthandler(req):
req.content_type = "text/plain"
req.write("Hello World!")
return apache.OK
Apache and Python with ModPython #1 (0) | 2008.10.12 |
---|---|
[Python]Content-Type= text/plain에서 text/plain이 무슨 의미인가여..? (0) | 2008.10.12 |
해결 하기 :
문제가 생기면 다음과 같은 방법으로 문제를 확인합니다. ㅎㅎ
에러 메시지 확인하기.
서버 에러 로그 확인 하기.
아파치를 커맨드 라인을 통해 싱글 프로세스 모드로 실행합니다.
./httpd -X
그러면 보다 유용한 정보를 알 수 있다고 합니다.
httpd.conf 파일에 아래의 글을 넣어 테스트 핸들러를 수행 할 수 있습니다.
<Location /mpinfo>
SetHandler mod_python
PythonHandler mod_python.testhandler
</Location>
그리고 브라우저를 통해 http://localhost/mpinfo 통해 에러정보를 알아 봅니다.
이도 저도 아니면? 아파치 버전이나 파이썬 버전 설정파일 코드등을 뭐 그런거 알아보라고 합니다. 당연히!
= 튜토리얼 =
이 튜토리얼을 읽어보고 Python API도 꼭 읽어 보라고 합니다. 왜? 중요한까!
Publisher Handler를 통해 빨리 알아보기 :
이 글은 Publisher Handler가 어떻게 동작하는지 빨리 간단히 알아보자 합니다. 더 자세한 내용은 마지막에 어떻게 작동하는지 설명하겠습니다. publisher handler는 표준 mod-python 입니다. 사용하기 위해서는 아파치에 아래처럼 셋팅합니다.
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
여기서는 간단히 피드백 폼을 만들어 보겠습니다. 이름하고 이메일 물어보고 관리자에게 보내지는 그런 폼이요. HTML 파일은
아래 처럼 만들어서 서버에 저장하면 됩니다.
<html>
Please provide feedback below:
<p>
<form action="form.py/email" method="POST">
Name: <input type="text" name="name"><br>
Email: <input type="text" name="email"><br>
Comment: <textarea name="comment" rows=4 cols=20></textarea><br>
<input type="submit">
</form>
</html>
HTML에 action을 form.py/email로 합니다. 그리고 우리는 form.py를 만들면 됩니다.
import smtplib
WEBMASTER = "webmaster" # webmaster e-mail
SMTP_SERVER = "localhost" # your SMTP server
def email(req, name, email, comment):
# make sure the user provided all the parameters
if not (name and email and comment):
return "A required parameter is missing, \
please go back and correct the error"
# create the message text
msg = """\
From: %s
Subject: feedback
To: %s
I have the following comment:
%s
Thank You,
%s
""" % (email, WEBMASTER, comment, name)
# send it out
conn = smtplib.SMTP(SMTP_SERVER)
conn.sendmail(email, [WEBMASTER], msg)
conn.quit()
# provide feedback to the user
s = """\
<html>
Dear %s,<br>
Thank You for your kind comments, we
will get back to you shortly.
</html>""" % name
return s
자 이렇게 쓰고 전송 버튼을 누르면 Publisher handler는 form 모듈의 email 함수를 호출합니다. 그리고 form 필드의 키워드 전달자에 값을 전달합니다. 이는 req라고 불리우는 request object를 통해서 전달됩니다. 그리고 데이터는 return 을 통해서 브라우저에 되돌려 집니다. publisher handler는 전달자를 보내기에 충분히 좋다고 하네요. 이는 파이썬을 간단히 써서 프로그램을 강력하게 만들어준답니다. 하지만 이걸 쓰고 싶지 않으면 native mod_python을 써서도 동일한 작동을 하게 만들 수 있다고 합니다.
예를 들어 사용자 header를 쓰고 싶으면 req.headers_out 를 써도 되고 apache.SERVER_ERROR 를 쓸 수도 있습니다.
아파치가 Requests 핸들하는 방법 빨리 알아보기 :
mod_python의 기능을 좀 더 깊이 알아보기 위해서는 아파치 handler가 하는 일을 알아야 합니다. 정말?
아파치는 몇개의 단계를 거쳐서 처리를 합니다. 먼저 사용자를 인증하고 사용자가 파일에 접촉할 수 있는지 검증하고 그리고
파일을 읽어서 사용자에게 보냅니다. 전형적인 정적 파일의 요청은 3가지의 단계를 거칩니다. 우선 파일의 위치를 URI로 변경하고
파일을 읽은 후에 클라이언트에게 보내고, 로그를 남깁니다. 오우! 뭐 이런 단계는 아파치 설정을 어떻게 하느냐에 따라 다르겠지만
여하튼 기본적으로는 그렇다고 합니다. handler는 첫번째 단계를 처리하는 기능입니다. 각 단계를 처리하는 하나 이상의 handler가
있을 수도 있습니다. 각각의 단계는 기본적으로 아파치의 handler를 사용하고 추가적인 handler는 아파치 모듈을 통해 지원됩니다.
mod_python 처럼요. mod_python은 아파치의 사용가능한 모든 handler를 지원합니다. 물론 아파치 서버 셋팅에 따라 다르겠지만요. Python이라고 시작하고 Handler라고 끝나는 단어는 예를 들어 PythonAuthenHandler 처럼 그 단계와 연결 됩니다. 그래서
mod_python의 분배자(dispatcher)는 아파치 핸들과 파이썬 함수에게 act 를 분해합니다. 흔히 쓰이는 건 PythonHandler 겠죠.
이건 요청의 단계에 작동하고 딱히 이름이 없기 때문에 generic handler라고 합니다. 이 Handler의 아파치 기본 행동은 파일을 읽고 클라이언트가 볼 수 있게 보내주는 것 입니다. Apache Directives 를 보면 더 자세하게 나옵니다. 그럼 ^^
Mod-python이 정말 뭘하는 건가? :
자! 자! 자! 우리가 아래와 같은 아파치 셋팅을 가지고 있다고 가정합시다.
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonDebug On
</Directory>
/mywebdir 은 절대 경로라고 생각하고요.
그리고 우리는 myscript.py라는 프로그램을 가지고 있다고 합시다. myscript.py는 아래의 코드에 나옵니다.
from mod_python import apache
def handler(req):
req.content_type = "text/plain"
req.write("Hello World!")
return apache.OK
그럼 우선 AddHandler부터 설명하는 이건 뭐하는 걸까요? 요건 아파치에게 .py를 확장자로 같는 파일에 대해서는 mod_python이 처리하도록 해줍니다. PythonHandler myscript 이건 파이썬에게 generic handler로 myscript.py를 처리하라는 말입니다. 그리고 PythonDebug는 사용자가 사용하다가 에러메시지를 볼 수 있도록 설정해주는 겁니다. 개발할때 매우 유용합니다.
그럼 요청이 들어오면요! 아파치는 mod_python의 요청을 담당하는 handler를 호출합니다. 그리고 어떤 handler가 담당할지 정합니다. 기억하세요. 이는 dispatcher 처럼 행동한 답니다. 우리 예제에서는 모든 handler에 대해서 (예외 generic handler) 아무런 작동도 안한답니다. 우리가 generic handler를 얻으면 mod_python은 PythonHandler myscript를 알리고 아래의 단계로 작동합니다.
from mod_python import apache
아파치 모듈을 불러옵니다. 예외가 있기는 하지만 거의 mod_python 함수는 이 라인을 가지고 있습니다.
def handler(req):handler 함수 입니다. mod_python은 handler를 호출합니다. 왜나햐면 mod_python이 이 이름으로 명령을 수행하기
때문입니다. 이건 소문자로 바뀌고 python.이라는 문자를 제거합니다. 고로 PythonHandler는 handler가 됩니다.
만약 다른 특정한 이름을 원한다면 '::'를 씁니다. 예를 들어 handler 함수가 spam이면 PythonHandler myscript::spam
이라고 써줍니다. 모든 함수는 최소 하나의 request object를 가져야합니다. request 객체는 현재 요청에 대한
모든 정보를 제공합니다. 예를 들어 IP나 URI 또는 헤더정보 등등등... 그리고 request 객체를 통해 요청이
완료 됩니다. request 객체는 있지만 response 객체는 없습니다.
req.content_type = "text/plain"이건 컨텐츠 정보입니다. 기본은 'text/html' 이고 우리 handler는 어떤 html 을 생성하는게 아니므로 그냥 plain
이 더 적절합니다. 중요!!!!!!!! 이건 꼭 req.write 이전에 있어야 합니다. 만약 먼저 오게 되면 HTTP 헤더를 단순히 잃어버립니다.
req.write("Hello World!")
뭐 설명이 필요한가요. Hello World를 찍겠다는 뜻입니다.
return apache.OK
아파치 서버에 모든게 OK 다 라고 표시해주는 겁니다. 만약 뭔가 잘못됐으면 return apache.HTTP_INTERNAL_SERVER_ERROR
return apache.HTTP_FORBIDDEN. 이걸 반환해 줍니다. 그럼 아파치는 로그를 남기고 사용자를 에러를 보게 됩니다.
잠깐 헛소리: 만약 특정한 파일이 아파치에 연결되지 않았다면 그냥 아무파일이나 연결됩니다. 고로 a.py건 myscript.py건 이름은
별로 중요하지 않습니다.
쫌 더 복잡한 이야기, 인증! :
이제 원초적인 Handler가 어떻게 작동하는지 알았습니다. 그런가? 그럼 이제 좀 더 복잡한 인증에 대해 알아보겠습니다.
인증이라! 자, 먼저 우리는 이 디렉토리에 암호를 걸기를 원합니다. 그러기 위해서는 우린 먼저 PythonAuthenHandler를 더합니다.
그럼 아래처럼 셋팅이 변경 되겠죠?
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
</Directory>
같은 스크립트가 두개의 다른 handler를 갖고 있습니다. 하지만 괜찮습니다. 이건 modpython이 다른 함수를 찾습니다.
이제 HTTP 기본인증을 하겠다는 말이죠! 오직 허락된 자만을 위해! 아래와 같습니다.
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
AuthType Basic
AuthName "Restricted Area"
require valid-user
</Directory>
" AuthAuthoritative
or AuthBasicAuthoritative
"를 통해 아파치 인증에 기댈 수 있습니다. 날 인증 시켜줘!
이제 인증을 위한 python 코드를 짜볼까요?
from mod_python import apache
def authenhandler(req):
pw = req.get_basic_auth_pw()
user = req.user
if user == "spam" and pw == "eggs":
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
함수는 이제 authenhandler를 찾습니다. 하나씩 따져 볼까요?
def authenhandler(req):
함수를 정의합니다. 앞에서 얘기했던것처럼 python 뺀 이름인 authenhandler입니다. 그리고 소문자로 바꿔주고!
pw = req.get_basic_auth_pw()
이제 암호를 얻습니다. 이건 HTTP 인증을 통해서 base64 인코딩된 값입니다. 이걸 디코딩해서 문자열로 반환해 줍니다.
이 함수는 사용자 이름을 얻기 전에 호출해 줘야 합니다.
user = req.user
사용자 이름을 얻습니다.
if user == "spam" and pw == "eggs":
사용자가 spam 이고 암호가 eggs면 OK 그리고 아파치의 다음 단계로 갑니다.
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
인증 실패를 반환해 줍니다. 그러면 브라우저로 아이디하고 패스워드를 묻는 걸 팝업해주면 되겠죠?
당신만의 404 에러 핸들링 :
이제 당신은 아마도! 404 HTTP_NOT_FOUND를 리턴하고 싶을 지도 모릅니다. 또는 202 결과를 당신의 Handler에서
리턴하고 싶을지도... 여하튼 여기 꽁수가 하나 있습니다. 아파치가 하겠지만 당신이 원하면 프로그램적으로 에러 페이지를
대체할 수 있습니다. 그때는 req.status = apache.HTTP_NOT_FOUND 해주고 당신의 페이지를 대체하고 ok 때려주면 됩니다.
from mod_python import apache
def handler(req):
if req.filename[-17:] == 'apache-error.html':
# make Apache report an error and render the error page
return(apache.HTTP_NOT_FOUND)
if req.filename[-18:] == 'handler-error.html':
# use our own error page
req.status = apache.HTTP_NOT_FOUND
pagebuffer = 'Page not here. Page left, not know where gone.'
else:
# use the contents of a file
pagebuffer = open(req.filename, 'r').read()
# fall through from the latter two above
req.write(pagebuffer)
return(apache.OK)
만약 다른 reponse handler에서 에러메시지를 반환하고 싶을 때에는 OK 대신 apache.DONE을 꼭 반환합니다. 그렇지 않으면
subsequent handler 가 계속 돌고 있을 껍니다. DONE 메시지는 처리를 바로 끝내라는 뜻입니다. 이건 이어지는
subsequent handlers를 방지할 수 있습니다.
Apache and Python with ModPython #2 (0) | 2008.10.12 |
---|---|
[Python]Content-Type= text/plain에서 text/plain이 무슨 의미인가여..? (0) | 2008.10.12 |
Apache and Python with ModPython #2 (0) | 2008.10.12 |
---|---|
Apache and Python with ModPython #1 (0) | 2008.10.12 |