Cafe24에서 Python CGI 돌리기
Cafe24에서 가상리눅스 호스팅 같은 걸 받으면 파이썬3도 설치할 수 있고 그렇다만, 여기서는 기본 호스팅에서 파이썬 CGI를 실행하는 방법을 살펴보도록 하자. (일단 파이썬 버전이 2.4이고 커스텀 모듈을 설치할 수도 없기 때문에 여러모로 좌절스럽긴 하다)
- CGI 파일의 위치는 특정한 위치에 들어갈 필요는 없다.
- 파일의 확장자는 반드시
.cgi
여야 한다..py
인 경우 일반 텍스트 파일처럼 처리된다. - 첫행은 반드시
#!/home/bin/python
이어야 한다. cafe24 매뉴얼에서#!/home/bin/python2
라고 무려 잘못된 내용을 안내해주고 있다. - 실행 권한은 상관없는 것 같기도 하다.
응답보내기
cgi에서 클라이언트로 응답을 보내는 경우, 파이썬 CGI는 사실상 웹서버의 역할을 아무것도 대행해주지 않는다. 진짜 말 그대로 인터페이스일 뿐이다. 따라서 Content-Type: text/html;\n\n
의 내용을 맨 위에 전송해주어야 한다. 그렇지 않은 경우 멋지게도 500 내부 에러가 나며, 에러 로그는 어디에도 남지 않는 것 같다.
이를 유의하면서 간단한 hello world 를 작성해보자.
#!/home/bin/python
# coding: utf-8
def main():
print """Content-Type: text/html
<html>
<head><title>test - hello world</title></head>
<body><h1>Hello, World!!! </h1></body></html>"""
if __name__ == "__main__":
main()
이 파일을 hello.cgi
등 적당한 이름으로 저장한 다음, 온전한 URL을 브라우저에 입력하면 익숙한 문구가 반겨줄 것이다.1
GET 파라미터 얻기
다행스럽게도 cgi
모듈은 폼이나 쿼리스트링을 자동으로 파싱해준다. 폼에서도 GET 전송은 가능하기 때문에 cgi.FieldStorage
는 요청 메소드가 GET인지 POST인지에 무관하게 이러한 각 필드 값을 사전 형식으로 가지고 있다.
메소드 찾기
요청의 메소드 타입은 환경 변수의 형태로 들어온다. 따라서 os
모듈이 필요하다.
# in CGI
import os
method = os.environ.get('REQUEST_METHOD', 'GET') # 없으면 GET으로...
if method == "POST":
# 포스트 요청을 핸들링한다.
pass
elif method == "GET":
# GET 요청을 핸들링한다.
pass
else:
# 그외의 요청을 처리한다.
pass
여튼 폼 전송된 각각의 인자값은 다음과 같이 처리한다.
import cgi
form = cgi.FieldStorage()
first_name = form.getvalue('first')
last_name = form.getvalue('last')
print """Content-Type:text/html
<html><head><title>test</title></head>
<body><h2>hello %s %s </h2></body></html>""" % (first_name, last_name)
이제 http://****/hello.cgi&last=cgi&first=python
이라고 접근해보면 Hello python cgi
라는 문구가 보일 것이다.
파일 업로드
파일을 업로드 받을 때에 CGI내에서 form.getvalue('file')
이라고 해버리면 해당 폼데이터 전체를 읽어들여 메모리로 가져오므로 이는 좋지 않다. 이 때는 그냥 form
자체를 하나의 사전으로 본다. (그러면 파일에 대한 참조만을 다루게 된다.) 그러면 이 객체는 filename
이나 file
속성을 통해서 파일에 대한 포인터 및 파일의 이름들을 액세스할 수 있다.
import os, cgi
form = cgi.FieldStorage()
_file = form['file']
if _file.filename:
# 파일이 왔을 때 파일이름으로 장난칠 수 있으므로...
fn = os.path.basename(_file.filename)
f = open('/tmp/' + fn, 'wb')
f.write(_file.file.read())
f.close()
파일 다운로드
바이너리 파일을 내려보낼 때 방법은 간략하게 다음과 같다.
#!/home/bin/python
# ...
print """Content-Type:application/octet-stream; name="Filename"
Content-Disposition:attachment; filename="Filename"
"""
f = open('file.bin', 'rb')
s = f.read()
print s
f.close()
생각해보니 파이썬3에서는 이렇게되면 문자열2이 아닌데 어떻게 출력해야하나 싶기도 하다.
참고로 이미지 파일의 경우에는 image/jpeg
등으로 할 수 있으며, JSON의 경우에는 applicationi/json
이다. 참고자료