콘텐츠로 건너뛰기
Home » Cafe24에서 Python CGI 돌리기

Cafe24에서 Python CGI 돌리기

Cafe24에서 Python CGI 돌리기

Cafe24에서 가상리눅스 호스팅 같은 걸 받으면 파이썬3도 설치할 수 있고 그렇다만, 여기서는 기본 호스팅에서 파이썬 CGI를 실행하는 방법을 살펴보도록 하자. (일단 파이썬 버전이 2.4이고 커스텀 모듈을 설치할 수도 없기 때문에 여러모로 좌절스럽긴 하다)

  1. CGI 파일의 위치는 특정한 위치에 들어갈 필요는 없다.
  2. 파일의 확장자는 반드시 .cgi 여야 한다. .py인 경우 일반 텍스트 파일처럼 처리된다.
  3. 첫행은 반드시 #!/home/bin/python 이어야 한다. cafe24 매뉴얼에서 #!/home/bin/python2라고 무려 잘못된 내용을 안내해주고 있다.
  4. 실행 권한은 상관없는 것 같기도 하다.

응답보내기

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이다. 참고자료


  1. 이 때 반드시 확장자가 .cgi 일 필요는 없다. 확장자는 상관없는 거 같으며, 특별히 별도의 cgi 디렉토리에 있을 필요도 없다. 
  2. 파이썬3의 CGI에서도 동일하게 문자열을 출력해주면 된다. CGI로 실행될 때는 표준 출력이 네트워크 포트가 되며, 이는 파이썬 환경에서 표준 출력의 인코딩을 결정해주기 때문에 문제가 되지 않는다.