다음과 같은 에러 메시지를 만나면 당황하게 됩니다.

  File "C:\Program Files\Google\google_appengine\google\appengine\tools\devappserver2\wsgi_server.py", line 31, in <module>

    from cherrypy import wsgiserver

  File "C:\Program Files\Google\google_appengine\lib\cherrypy\cherrypy\__init__.py", line 70, in <module>

    from cherrypy import _cptools

  File "C:\Program Files\Google\google_appengine\lib\cherrypy\cherrypy\_cptools.py", line 245, in <module>

    from cherrypy.lib import cptools, encoding, auth, static, jsontools

  File "C:\Program Files\Google\google_appengine\lib\cherrypy\cherrypy\lib\static.py", line 7, in <module>

    mimetypes.init()

  File "C:\Python27\lib\mimetypes.py", line 358, in init

    db.read_windows_registry()

  File "C:\Python27\lib\mimetypes.py", line 258, in read_windows_registry

    for subkeyname in enum_types(hkcr):

  File "C:\Python27\lib\mimetypes.py", line 249, in enum_types

    ctype = ctype.encode(default_encoding) # omit in 3.x!

UnicodeDecodeError: 'ascii' codec can't decode byte 0xb1 in position 9: ordinal not in range(128)



C:\Python27\Lib 폴더의 mimetypes.py 249번째 줄에서 발생한 에러입니다.


편집기로 열어서 지우거나 앞에 #을 붙여서 주석처리합니다.

끝!


추가로 메모장에서 한글을 사용하는 경우, 파일 > 다른 이름으로 저장 메뉴를 선택하고 인코딩을 UTF-8로 저장하는 것을 추천합니다.


안녕, World! 보기 쉽지 않네요.



관련 글: http://stackoverflow.com/questions/4237898/unicodedecodeerror-ascii-codec-cant-decode-byte-0xe0-in-position-0-ordinal/4238212#4238212



구글 앱엔진 시작하기 윈도우XP 편


구글 앱엔진 애플리케이션 업로드



윈도우에서 구글 앱 엔진을 돌려 봤습니다. 파이썬으로 작업을 하면서 삽질을 조금했기 때문에 기록을 남겨봅니다. 현재 구글앱엔진은 파이썬 2.7을 공식 지원합니다. python 3.x은 지원하지 않습니다. 때문에 python27을 다시 설치했습니다.(삽질1)


절차는 다음과 같습니다.

part 1 앱 엔진 등록

1.1 http://appengine.google.com/ 사이트에 구글 계정으로 등록을 합니다. 휴대폰인증이 있습니다.

1.2 앱엔진 애플리케이션을 만듭니다. Application Identifier(예, khcuweb)가 정해지면 http://khcuweb.appspot.com 로 접근하게 됩니다.


part 2 로컬 개발환경

2.1 구글앱엔진 SDK 파이썬 버전을 다운로드 받아서 설치합니다.

2.2 http://python.org 사이트에서 Python 2.7을 다운로드 받아서 설치합니다.

2.3 환경 변수 > 사용자 변수 Path에 C:\Program Files\Google\google_appengine\ 경로 추가된 것 확인

2.4 환경 변수 > 시스템 변수 Path에 C:\Python27;C:\Python27\Scripts; 경로를 추가합니다.


part 3

3.1 helloworld.py 만들기

3.2 app.yaml 만들기

3.3 dev_appserver.py helloworld.py 실행하기 

윈도우 XP에서 UnicodeDecodeError 발생하는데, 이에 관해서는 다음 글에 올리겠습니다.












구글의 앱 엔진(http://appengine.appspot.com/)은 데이터를 저장할 때 비용이 발생합니다. SQL을 사용하려면 더 비쌉니다.

간단히 데이터를 저장하고 빼는 방법으로 DataStore API를 제공해줍니다. 그리고, 저장된 데이터는 관리자 웹 페이지를 통해서 확인할 수 있습니다.


저장하는 절차는 다음과 같습니다.

1. 환경에서 DatastoreService를 가져옵니다.

2. Key를 만듭니다. Key의 종류와 key 이름을 추가합니다.

3. 레코드는 Entity 클래스를 이용합니다.

4. entity에 key : value 형식으로 기록할 데이터를 입력합니다.

5. Datastore에 entity를 추가합니다.


private static final String KEY_KIND = "Game";

private static final String keyName = "games";


DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();


public void save(Game game) {

Key entityKey = KeyFactory.createKey(KEY_KIND, keyName);


Entity entity = new Entity(KEY_KIND, entityKey);


User firstUser = game.getFirstUser();

User secondUser = game.getSecondUser();


entity.setProperty("first", firstUser.getName());

entity.setProperty("firstchoice", firstUser.getChoice());

entity.setProperty("second", secondUser.getName());

entity.setProperty("secondchoice", secondUser.getChoice());


entity.setProperty("datetime", new Date());

entity.setProperty("ip", game.getIp());


datastore.put(entity);

}



관리자 페이지에서는 다음과 같이 화면이 제공됩니다.




데이터를 꺼내오는 방법은 다음과 같습니다.


1. Key를 만듭니다.

2. Query를 만들면서 정렬순서와 기준 항목을 정합니다.

3. Datastore에서 Query를 이용해서 데이터를 꺼냅니다.

4. Entity 목록을 처리합니다.

public List<Entity> fetchAll() {

Key entityKey = KeyFactory.createKey(KEY_KINDkeyName);

Query query = new Query(KEY_KIND, entityKey).addSort("datetime",

Query.SortDirection.DESCENDING);

List<Entity> games = datastore.prepare(query).asList(

FetchOptions.Builder.withLimit(5));


return games;

}




한참을 삽질했습니다. 구글링을 해보니 mac의 jdk와 호환이 되지 않아서 발생하는 문제라고 합니다.

http://stackoverflow.com/questions/17822795/google-app-engine-javax-servlet-unavailableexception-initialization-failed#comment27168122_17822795


역시나 윈도우 가상머신에 GAE 개발환경 갖추고 실행하니 같은 소스가 잘 동작합니다.



다음은 앱엔진 로그에 나타나는 메시지입니다.

  1. 2013-10-15 16:22:29.386 / 500 5066ms 0kb Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1
    210.98.50.4 - - [15/Oct/2013:16:22:29 -0700] "GET / HTTP/1.1" 500 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1" "1.okgawi.appspot.com" ms=5067 cpu_ms=2567 loading_request=1 app_engine_release=1.8.6 instance=00c61b117cc605edbcad33f6d430edbd601896
  2. W2013-10-15 16:22:29.299
    EXCEPTION 
    java.lang.IllegalArgumentException
    	at com.google.appengine.runtime.Request.process-3c18ce8f0ef50d07(Request.java)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:360)
    	at org.mortbay.util.Loader.loadClass(Loader.java:91)
    	at org.mortbay.util.Loader.loadClass(Loader.java:71)
    	at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:73)
    	at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    	at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    	at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    	at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    	at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:435)
    	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:442)
    	at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:186)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:306)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:298)
    	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:439)
    	at java.lang.Thread.run(Thread.java:724)
    
  3. E2013-10-15 16:22:29.376
    javax.servlet.ServletContext log: unavailable
    javax.servlet.UnavailableException
    	at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:79)
    	at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    	at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    	at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    	at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    	at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
    	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
    	at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
    	at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
    	at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:435)
    	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:442)
    	at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:186)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:306)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:298)
    	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:439)
    	at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
    	at java.lang.Thread.run(Thread.java:724)
    
  4. W2013-10-15 16:22:29.380
    Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@1d9525e{/,/base/data/home/apps/s~okgawi/1.370945407503011368}
    java.lang.NullPointerException
    	at java.lang.Class.isAssignableFrom(Native Method)
    	at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:256)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)
    	at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
    	at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
    	at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
    	at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
    	at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
    	at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
    	at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
    	at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
    	at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:435)
    	at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:442)
    	at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:186)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:306)
    	at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:298)
    	at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:439)
    	at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
    	at java.lang.Thread.run(Thread.java:724)



쉬운 게 없군요.


요즘 파이썬을 배우는 분들에게 추천해 봅니다. python2.5버전 기준의 개(GAE; Google App Engine)를 설명합니다만 300페이지 안되는 분량에서 제법 많은 것들을 다뤄줍니다. 웹 프레임워크는 Django(장고)를 사용합니다.


구글 앱 엔진에 파이썬으로 프로그래밍을 시작하는 분들에게 적합합니다. 그리고 웹 개발을 처음 배우시는 분들에게 HTML, CSS, JavaScript, jQuery까지 단계적으로 핵심을 알려줍니다. 초고속 과외라고 할 수 있습니다. 


구글 앱 엔진을 통해서 배우는 파이썬이라고 총평하고 싶네요.




http://www.appenginelearn.com/

원 저자 찰스 세프란스가 운영하는 페이지입니다. 강의 PDF와 책의 예제를 다운로드 받을 수 있습니다. 

번역도 무난하게 잘 되어 있습니다. 역자주도 개념을 잡는 데 도움을 줍니다.


http://okae-12-ajax.appspot.com/

ae-12-ajax.appspot.com 을 올려보았습니다. 

주의) 회원가입시 사용한 비번은 회원들에게 보여집니다. ^^;



삭제, 탈퇴는 관리자만 가능합니다.

http://appengine.google.com







Activity라고 하니 안드로이드가 생각나네요.
인스턴스의 성능에 따라서 가격이 다르게 매겨집니다. Amazon EC2 서버 241시간에 $20.49인데 반해서 SUSE Linux는 9시간 $3.96, 8시간 2.16으로 정산되는군요.
ROOT권한을 갖고 서버를 다룰 수 있기 때문에 테스트용으로는 괜찮은 선택이라 생각됩니다.

$27는 학습을 위한 비용입니다.


Amazon과 비슷한 서비스로 제한적으로 무료인 구글 앱 엔진도 있습니다.

+ Recent posts