먼저 토네이도를 선택하는 이유:
1. gevent, Twisted, libevent 등과 함께 사용할 수 있는 고성능 네트워크 라이브러리
비동기 IO 지원, 타임아웃 이벤트 처리 기능을 제공하며, 이를 기반으로 tcpserver, httpclient, 특히 curhttpclient
를 제공합니다.
기존 http 클라이언트 중 확실히 1위를 차지하고 있습니다. 제가 아는 한, 업계에서는 토네이도를 게임 서버로 사용해 왔습니다
2. django 및 Flask와 비교할 수 있는 웹 프레임워크입니다.
라우팅, 템플릿 등 웹 프레임워크의 필수 구성 요소를 제공합니다. 다른 것과 다른 점은 토네이도가 비동기식이며 자연스럽게 장거리 훈련에 적합하다는 것입니다.
프렌드피드가 토네이도를 발명한 이유이기도 합니다. 현재 플라스크에서도 지원이 가능하지만 gevent 등을 사용해야 합니다.
3. nginx 및 apache와 비교할 수 있는 비교적 완전한 http 서버
하지만 http1.0만 지원하므로 nginx를 프론트엔드로 사용하는 것은 멀티코어를 더 잘 활용할 수 있을 뿐만 아니라 http1.1도 지원한다는 뜻입니다
4. gunicore 및 gevent wsgi 서버와 비교할 수 있는 완전한 wsgi 서버
즉, 플라스크를 토네이도 위에 올려놓고 토네이도가 플라스크를 가속하게 할 수 있습니다
5. 완전한 웹소켓 지원을 제공하여 HTML5 게임을 편리하게 만듭니다.
예를 들어 Zhihu 긴 회전 훈련은 websocket을 사용하지만 websocket 휴대폰 지원은 그다지 좋지 않습니다.
얼마 전에는 예약된 Ajax를 사용하여 많은 요청을 보내야 했습니다. 모바일 브라우저가 곧 따라잡았으면 좋겠습니다.
토네이도를 활용해 간단한 책 소개 페이지 만들기
자, 본론으로 들어가 이 책 소개 페이지의 코드 구현을 살펴보겠습니다.
1. 웹 서비스 항목 파일 blockmain.py를 생성합니다
#coding:utf-8 import tornado.web import tornado.httpserver import tornado.ioloop import tornado.options import os.path import json import urllib2 from tornado.options import define, options define("port", default=8000, help="run on the given port", type=int) class MainHandler(tornado.web.RequestHandler): def get(self): self.render( "index.html", page_title = "Burt's Books ¦ Home", header_text = "Welcome to Burt's Books!", books = ['细说php','python','PHP','小时代'] ) class HelloModule(tornado.web.UIModule): def render(self): return'<h1>I am yyx and this is an information from module hello!</h1>' class BookModule(tornado.web.UIModule): def render(self,bookname): doubanapi = r'https://api.douban.com/v2/book/' searchapi = r'https://api.douban.com/v2/book/search?q=' searchurl = searchapi+bookname searchresult = urllib2.urlopen(searchurl).read() bookid = json.loads(searchresult)['books'][0]['id'] bookurl = doubanapi+bookid injson = urllib2.urlopen(bookurl).read() bookinfo = json.loads(injson) return self.render_string('modules/book.html',book = bookinfo) def embedded_javascript(self): return "document.write(\"hi!\")" def embedded_css(self): return '''.book {background-color:#F5F5F5} .book_body{color:red} ''' def html_body(self): return '<script>document.write("Hello!")</script>' if __name__ == "__main__": tornado.options.parse_command_line() app = tornado.web.Application( handlers = [ (r'/',MainHandler), ], template_path = os.path.join(os.path.dirname(__file__),'templates'), static_path = os.path.join(os.path.dirname(__file__),'static'), debug = True, ui_modules={'Hello':HelloModule,'Book':BookModule} ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
몇 가지 기본 MVC 개념 설명:
Tornado는 또한 pathinfo 모드를 사용하여 사용자의 입력을 일치시켜 매개변수를 얻은 다음 해당 처리 함수를 호출하여 다양한 일치 모드에 대해 해당 클래스 클래스를 설정하여 처리합니다. 예를 들어, MainHandler 클래스를 사용하여 / get에서 데이터를 처리합니다. 요청
MainHandler는 index.html에 대한 요청을 렌더링하고 매개변수는 index.html
2. 해당 템플릿을 만듭니다. 먼저 기본 상위 클래스 main.html 템플릿을 만들고 그 아래에 main.html을 만듭니다. 이 템플릿은 가장 기본적인 웹 페이지 프레임워크만 정의하며, 구체적인 내용은 다음과 같습니다. 하위 클래스에서 상속하여 구체적으로 구현합니다
<html> <head> <title>{{ page_title }}</title> <link rel="stylesheet" href="{{ static_url("css/style.css") }}" /> </head> <body> <div id="container"> <header> {% block header %}<h1>Burt's Books</h1>{% end %} </header> <div id="main"> <div id="content"> {% block body %}{% end %} </div> </div> <footer> {% set mailLink = '<a href="mailto:contact@burtsbooks.com">Contact Us</a>' %} {% set script = '<script>alert("hello")</script>' %} {% block footer %} <p> For more information about our selection, hours or events, please email us at{% raw mailLink %} <!-- {% raw script %} 这里将原样输出,也就是会弹一个框--> </p> {% end %} </footer> </div> <script src="{{ static_url("js/script.js") }}"></script> </body> </html>
여기에 정의된 메인 프레임이 있는데, 여기서 {% block header %}4a249f0d628e2318394fd9b75b4636b1Burt's Books473f0a7621bec819994bb5020d29372a{% end %}는 서브클래스 템플릿의 상속을 위한 블록입니다. 클래스는 이를 상속합니다. main.html. 이 블록에 작성된 특정 콘텐츠는 하위 클래스에 의해 구현됩니다. 구현되지 않은 경우 상위 클래스의 기본값이 사용됩니다. 예를 들어 여기에서는 4a249f0d628e2318394fd9b75b4636b1Burt's Books473f0a7621bec819994bb5020d29372a MainHandler 클래스는 index.html로 렌더링된 다음 index.html을 작성하여 이 상위 클래스를 상속합니다.
{% extends "main.html" %} {% block header %} <h1>{{ header_text }}</h1> {% end %} {% block body %} <div id="hello"> <p>Welcome to Burt's Books!</p> {% module Hello() %} {% for book in books %} {% module Book(book) %} {% end %} <p>...</p> </div> {% end %}
간단하고 간결합니다. 상속을 사용하면 부모 클래스에 내용을 반복해서 작성할 필요가 없습니다.
MainHandler 클래스
의 렌더링 메소드에 있는 매개변수
page_title = "Burt's Books | Home", header_text = "Welcome to Burt's Books!", books = ['细说php','python','PHP','小时代']
여기로 매개변수를 통해 전송됩니다
토네이도 템플릿에 Python 코드를 사용하고, if for while 등을 사용할 때는 끝에 {% end %}를 사용하세요
코드에서 {% module Book(book) %}는 항목 서비스 파일의 정의와 'Book'에 해당하는 모듈을 호출합니다
ui_modules={'Hello':HelloModule,'Book':BookModule}은 BookModule입니다. 위의 BookModule 정의를 확인하세요
class BookModule(tornado.web.UIModule): def render(self,bookname): doubanapi = r'https://api.douban.com/v2/book/' searchapi = r'https://api.douban.com/v2/book/search?q=' searchurl = searchapi+bookname searchresult = urllib2.urlopen(searchurl).read() bookid = json.loads(searchresult)['books'][0]['id'] bookurl = doubanapi+bookid injson = urllib2.urlopen(bookurl).read() bookinfo = json.loads(injson) return self.render_string('modules/book.html',book = bookinfo)
BookModule은 tornado.web.UIModule을 상속받습니다. UI 모듈의 사용은 객체를 템플릿으로 렌더링하는 render_string() 메서드입니다. 여기서는 단순히 Douban의 책 API를 사용하고 먼저 검색을 통해 쿼리했습니다. 키워드를 사용하여 첫 번째 책의 ID를 반환한 다음 책 API를 사용하여 책의 특정 정보를 쿼리하고 이 특정 책의 정보를 해당 템플릿으로 렌더링합니다
템플릿 디렉토리 아래에 모듈 디렉토리를 생성한 후 book.html을 생성합니다. 책에 표시할 특정 콘텐츠 프레임워크는 다음과 같습니다
<div class="book"> <h3 class="book_title">{{ book["title"] }}</h3> <a href="{{book['alt']}}" target="_blank"><p>点击查看详情</p></a> {% if book["subtitle"] != "" %} <h4 class="book_subtitle">{{ book["subtitle"] }}</h4> {% end %} <img src="{{ book["images"]["large"] }}" class="book_image"/> <div class="book_details"> <div class="book_date_released">Released: {{ book["pubdate"]}}</div> <h5>Description:</h5> <div class="book_body">{% raw book["summary"] %}</div> </div> </div>
최종 파일 디렉터리 구조는 다음과 같습니다
├── blockmain.py └── templates ├── index.html ├── main.html └── modules └── book.html
프로그램 실행은 다음과 같습니다.
먼저 MainHandler 클래스를 사용하여 index.html의 '/'---->index.html은 main.html에서 상속받습니다.--->{% module Book(book) %} 경로를 통해 index.html에 액세스하고 그 반대의 경우도 마찬가지입니다. blockmain.py---->ui_modules에서 Book에 해당하는 ui_modules를 찾고 쿼리된 책 개체 콘텐츠를 모듈 아래 book.html로 렌더링하여 프런트 엔드를 수행하지 않고도 전체 콘텐츠가 표시되도록 합니다. python blockmain.py를 통해 서비스를 제공하고 http://localhost:8000
을 통해 다음 웹페이지에 접속합니다.