上一篇介绍了客户端请求在tornado框架中的生命周期,其本质就是利用epoll和socket来获取并处理请求。在上一篇的内容中,我们只是给客户端返回了简单的字符串,如:“Hello World”,而在实际开发中,需要使用html文件的内容作为模板,然后将被处理后的数据(计算或数据库中的数据)嵌套在模板中,然后将嵌套了数据的html文件的内容返回给请求者客户端,本篇就来详细的剖析模板处理的整个过程。

概述

上图是返回给用户一个html文件的整个流程,较之前的Demo多了绿色流线的步骤,其实就是把【self.write('hello world')】变成了【self.render('main.html')】,对于所有的绿色流线只做了五件事:

  • 使用内置的open函数读取Html文件中的内容
  • 根据模板语言的标签分割Html文件的内容,例如:{{}} 或 {%%}
  • 将分割后的部分数据块格式化成特殊的字符串(表达式)
  • 通过python的内置函数执行字符串表达式,即:将html文件的内容和嵌套的数据整合
  • 将数据返回给请求客户端

所以,如果要返回给客户端对于一个html文件来说,根据上述的5个阶段其内容的变化过程应该是这样

  1. class MainHandler(tornado.web.RequestHandler):
  2. def get(self):
  3. self.render("main.html",**{'data':['11','22','33'],'title':'main'})
  4.  
  5. [main.html]
  6. <!DOCTYPE html>
  7. <html>
  8. <head lang="en">
  9. <meta charset="UTF-8">
  10. <title></title>
  11. </head>
  12. <body>
  13. <h1>{{title}}</h1>
  14.  
  15. {% for item in data %}
  16. <h3>{{item}}</h3>
  17. {% end %}
  18. </body>
  19. </html>

myHandler.get

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <h1>{{title}}</h1>
  9.  
  10. {% for item in data %}
  11. <h3>{{item}}</h3>
  12. {% end %}
  13. </body>
  14. </html>
  15.  
  16. 1.根据open函数读取html文件内容

1.根据open函数读取html文件内容

  1. 1块:'<!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title></title></head><h1>'
  2. 2块:'title'
  3. 3块:'</h1> \n\n'
  4. 4块:'for item in data'
  5. 4.1块:'\n <h3>'
  6. 4.2块:'item'
  7. 4.3块:'</h3> \n'
  8. 第五块:'</body>'
  9.  
  10. 2.html内容分块

2.将html内容分块

  1. 'def _execute():
  2. _buffer = []
  3. _buffer.append(\\'<!DOCTYPE html>\\n<html>\\n<head lang="en">\\n<meta charset="UTF-8">\\n<title></title>\\n</head>\\n<body>\\n<h1>\\')
  4. _tmp = title
  5. if isinstance(_tmp, str): _buffer.append(_tmp)
  6. elif isinstance(_tmp, unicode): _buffer.append(_tmp.encode(\\'utf-8\\'))
  7. else: _buffer.append(str(_tmp))
  8. _buffer.append(\\'</h1>\\n\\')
  9. for item in data:
  10. _buffer.append(\\'\\n<h3>\\')
  11. _tmp = item
  12. if isinstance(_tmp, str): _buffer.append(_tmp)
  13. elif isinstance(_tmp, unicode): _buffer.append(_tmp.encode(\\'utf-8\\'))
  14. else: _buffer.append(str(_tmp))
  15. _buffer.append(\\'</h3>\\n\\')
  16. _buffer.append(\\'\\n</body>\\n</html>\\')
  17. return \\'\\'.join(_buffer)
  18. '

3.将分块的内容进行处理成特殊的特殊的字符串

  1. a、参照本篇博文的前戏 http://www.cnblogs.com/jasonwang-2016/p/5953009.html
  2. b、全局变量有 title 'main';data = ['11','22','33']

4.执行字符串表示的函数

在第4步中,执行第3步生成的字符串表示的函数后得到的返回值就是要返回给客户端的响应信息主要内容。

3.13、RequestHandler的render方法

此段代码主要有三项任务:

  • 获取Html文件内容并把数据(程序数据或框架自带数据)嵌套在内容中的指定标签中(本篇主题)
  • 执行ui_modules,再次在html中插入内容,例:head,js文件、js内容、css文件、css内容和body
  • 内部调用客户端socket,将处理请求后的数据返回给请求客户端
  1. class RequestHandler(object):
  2.  
  3. def render(self, template_name, **kwargs):
  4. #根据Html文件名称获取文件内容并把参数kwargs嵌入到内容的指定标签内
  5. html = self.render_string(template_name, **kwargs)
  6.  
  7. #执行ui_modules,再在html的内容中插入head,js文件、js内容、css文件、css内容和body信息。
  8. js_embed = []
  9. js_files = []
  10. css_embed = []
  11. css_files = []
  12. html_heads = []
  13. html_bodies = []
  14. for module in getattr(self, "_active_modules", {}).itervalues():
  15. embed_part = module.embedded_javascript()
  16. if embed_part: js_embed.append(_utf8(embed_part))
  17. file_part = module.javascript_files()
  18. if file_part:
  19. if isinstance(file_part, basestring):
  20. js_files.append(file_part)
  21. else:
  22. js_files.extend(file_part)
  23. embed_part = module.embedded_css()
  24. if embed_part: css_embed.append(_utf8(embed_part))
  25. file_part = module.css_files()
  26. if file_part:
  27. if isinstance(file_part, basestring):
  28. css_files.append(file_part)
  29. else:
  30. css_files.extend(file_part)
  31. head_part = module.html_head()
  32. if head_part: html_heads.append(_utf8(head_part))
  33. body_part = module.html_body()
  34. if body_part: html_bodies.append(_utf8(body_part))
  35. if js_files:#添加js文件
  36. # Maintain order of JavaScript files given by modules
  37. paths = []
  38. unique_paths = set()
  39. for path in js_files:
  40. if not path.startswith("/") and not path.startswith("http:"):
  41. path = self.static_url(path)
  42. if path not in unique_paths:
  43. paths.append(path)
  44. unique_paths.add(path)
  45. js = ''.join('<script src="' + escape.xhtml_escape(p) +
  46. '" type="text/javascript"></script>'
  47. for p in paths)
  48. sloc = html.rindex('</body>')
  49. html = html[:sloc] + js + '\n' + html[sloc:]
  50. if js_embed:#添加js内容
  51. js = '<script type="text/javascript">\n//<![CDATA[\n' + \
  52. '\n'.join(js_embed) + '\n//]]>\n</script>'
  53. sloc = html.rindex('</body>')
  54. html = html[:sloc] + js + '\n' + html[sloc:]
  55. if css_files:#添加css文件
  56. paths = []
  57. unique_paths = set()
  58. for path in css_files:
  59. if not path.startswith("/") and not path.startswith("http:"):
  60. path = self.static_url(path)
  61. if path not in unique_paths:
  62. paths.append(path)
  63. unique_paths.add(path)
  64. css = ''.join('<link href="' + escape.xhtml_escape(p) + '" '
  65. 'type="text/css" rel="stylesheet"/>'
  66. for p in paths)
  67. hloc = html.index('</head>')
  68. html = html[:hloc] + css + '\n' + html[hloc:]
  69. if css_embed:#添加css内容
  70. css = '<style type="text/css">\n' + '\n'.join(css_embed) + \
  71. '\n</style>'
  72. hloc = html.index('</head>')
  73. html = html[:hloc] + css + '\n' + html[hloc:]
  74. if html_heads:#添加htmlheader
  75. hloc = html.index('</head>')
  76. html = html[:hloc] + ''.join(html_heads) + '\n' + html[hloc:]
  77. if html_bodies:#添加htmlbody
  78. hloc = html.index('</body>')
  79. html = html[:hloc] + ''.join(html_bodies) + '\n' + html[hloc:]
  80.  
  81. #把处理后的信息响应给客户端
  82. self.finish(html)

RequestHandler.render

对于上述三项任务,第一项是模板语言的重中之重,读取html文件并将数据嵌套到指定标签中,以下的步骤用于剖析整个过程(详情见下文);第二项是对返会给用户内容的补充,也就是在第一项处理完成之后,利用ui_modules再次在html中插入内容(head,js文件、js内容、css文件、css内容和body);第三项是通过socket将内容响应给客户端(见上篇)。

对于ui_modules,每一个ui_module其实就是一个类,一旦注册并激活了该ui_module,tornado便会自动执行其中的方法:embedded_javascript、javascript_files、embedded_css、css_files、html_head、html_body和render ,从而实现对html内容的补充。(执行过程见上述代码)

自定义UI Modules

此处是一个完整的 创建 --> 注册 --> 激活 的Demo

目录结构:

  ├── index.py
  ├── static
  └── views
     └── index.html

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import tornado.ioloop
  5. import tornado.web
  6.  
  7. class CustomModule(tornado.web.UIModule):
  8. def embedded_javascript(self):
  9. return 'embedded_javascript'
  10.  
  11. def javascript_files(self):
  12. return 'javascript_files'
  13.  
  14. def embedded_css(self):
  15. return 'embedded_css'
  16.  
  17. def css_files(self):
  18. return 'css_files'
  19.  
  20. def html_head(self):
  21. return 'html_head'
  22.  
  23. def html_body(self):
  24. return 'html_body'
  25.  
  26. def render(self):
  27. return 'render'
  28.  
  29. class MainHandler(tornado.web.RequestHandler):
  30.  
  31. def get(self):
  32. self.render('index.html')
  33.  
  34. settings = {
  35. 'static_path': 'static',
  36. "template_path": 'views',
  37. "ui_modules": {'Foo': CustomModule},
  38. }
  39.  
  40. application = tornado.web.Application([(r"/", MainHandler), ], **settings)
  41.  
  42. if __name__ == "__main__":
  43. application.listen(8888)
  44. tornado.ioloop.IOLoop.instance().start()

index.py

  1. !DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8.  
  9. <hr>
  10. {% module Foo() %}
  11. <hr>
  12.  
  13. </body>
  14. </html>

index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <!-- css_files -->
  7. <link href="/static/css_files" type="text/css" rel="stylesheet">
  8.  
  9. <!-- embedded_css -->
  10. <style type="text/css">
  11. embedded_css
  12. </style>
  13.  
  14. </head>
  15. <body>
  16.  
  17. <!-- html_head -->
  18. html_head
  19.  
  20. <hr>
  21. <!-- redner -->
  22. render
  23. <hr>
  24.  
  25. <!-- javascript_files -->
  26. <script src="/static/javascript_files" type="text/javascript"></script>
  27.  
  28. <!-- embedded_javascript -->
  29. <script type="text/javascript">
  30. //<![CDATA[
  31. embedded_javascript
  32. //]]>
  33. </script>
  34.  
  35. <!-- html_body -->
  36. html_body
  37.  
  38. </body>
  39. </html>

执行结果

该方法是本篇的重中之重,它负责去处理Html模板并返回最终结果,【概述】中提到的5件事中前四件都是此方法来完成的,即:

    1. 创建Loader对象,并执行load方法
          -- 通过open函数打开html文件并读取内容,并将内容作为参数又创建一个 Template 对象
          -- 当执行Template的 __init__ 方法时,根据模板语言的标签 {{}}、{%%}等分割并html文件,最后生成一个字符串表示的函数
    2. 获取所有要嵌入到html模板中的变量,包括:用户返回和框架默认
    3. 执行Template对象的generate方法
          -- 编译字符串表示的函数,并将用户定义的值和框架默认的值作为全局变量
          -- 执行被编译的函数获取被嵌套了数据的内容,然后将内容返回(用于响应给请求客户端)

注意:详细编译和执行Demo请参见《tornado源码之褪去模板外衣的前戏 》

  1. class RequestHandler(object):
  2.  
  3. def render_string(self, template_name, **kwargs):
  4.  
  5. #获取配置文件中指定的模板文件夹路径,即:template_path = 'views'
  6. template_path = self.get_template_path()
  7.  
  8. #如果没有配置模板文件的路径,则默认去启动程序所在的目录去找
  9. if not template_path:
  10. frame = sys._getframe(0)
  11. web_file = frame.f_code.co_filename
  12. while frame.f_code.co_filename == web_file:
  13. frame = frame.f_back
  14. template_path = os.path.dirname(frame.f_code.co_filename)
  15. if not getattr(RequestHandler, "_templates", None):
  16. RequestHandler._templates = {}
  17.  
  18. #创建Loader对象,第一次创建后,会将该值保存在RequestHandler的静态字段_template_loaders中
  19. if template_path not in RequestHandler._templates:
  20. loader = self.application.settings.get("template_loader") or\
  21. template.Loader(template_path)
  22. RequestHandler._templates[template_path] = loader
  23.  
  24. #执行Loader对象的load方法,该方法内部执行执行Loader的_create_template方法
  25. #在_create_template方法内部使用open方法会打开html文件并读取html的内容,然后将其作为参数来创建一个Template对象
  26. #Template的构造方法被执行时,内部解析html文件的内容,并根据内部的 {{}} {%%}标签对内容进行分割,最后生成一个字符串类表示的函数并保存在self.code字段中
  27. t = RequestHandler._templates[template_path].load(template_name)
  28.  
  29. #获取所有要嵌入到html中的值和框架默认提供的值
  30. args = dict(
  31. handler=self,
  32. request=self.request,
  33. current_user=self.current_user,
  34. locale=self.locale,
  35. _=self.locale.translate,
  36. static_url=self.static_url,
  37. xsrf_form_html=self.xsrf_form_html,
  38. reverse_url=self.application.reverse_url
  39. )
  40. args.update(self.ui)
  41. args.update(kwargs)
  42.  
  43. #执行Template的generate方法,编译字符串表示的函数并将namespace中的所有key,value设置成全局变量,然后执行该函数。从而将值嵌套进html并返回。
  44. return t.generate(**args)
  1. class Loader(object):
  2. """A template loader that loads from a single root directory.
  3.  
  4. You must use a template loader to use template constructs like
  5. {% extends %} and {% include %}. Loader caches all templates after
  6. they are loaded the first time.
  7. """
  8. def __init__(self, root_directory):
  9. self.root = os.path.abspath(root_directory)
  10. self.templates = {}

Loader.__init__

  1. class Loader(object):
  2. def load(self, name, parent_path=None):
  3. name = self.resolve_path(name, parent_path=parent_path)
  4. if name not in self.templates:
  5. path = os.path.join(self.root, name)
  6. f = open(path, "r")
  7. #读取html文件的内容
  8. #创建Template对象
  9. #name是文件名
  10. self.templates[name] = Template(f.read(), name=name, loader=self)
  11. f.close()
  12. return self.templates[name]

Loder.load

  1. class Template(object):
  2.  
  3. def __init__(self, template_string, name="<string>", loader=None,compress_whitespace=None):
  4. # template_string是Html文件的内容
  5.  
  6. self.name = name
  7. if compress_whitespace is None:
  8. compress_whitespace = name.endswith(".html") or name.endswith(".js")
  9.  
  10. #将内容封装到_TemplateReader对象中,用于之后根据模板语言的标签分割html文件
  11. reader = _TemplateReader(name, template_string)
  12.  
  13. #分割html文件成为一个一个的对象
  14. #执行_parse方法,将html文件分割成_ChunkList对象
  15. self.file = _File(_parse(reader))
  16.  
  17. #将html内容格式化成字符串表示的函数
  18. self.code = self._generate_python(loader, compress_whitespace)
  19.  
  20. try:
  21. #将字符串表示的函数编译成函数
  22. self.compiled = compile(self.code, self.name, "exec")
  23.  
  24. except:
  25. formatted_code = _format_code(self.code).rstrip()
  26. logging.error("%s code:\n%s", self.name, formatted_code)
  27. raise

Template.__init__

  1. class Template(object):
  2. def generate(self, **kwargs):
  3. """Generate this template with the given arguments."""
  4. namespace = {
  5. "escape": escape.xhtml_escape,
  6. "xhtml_escape": escape.xhtml_escape,
  7. "url_escape": escape.url_escape,
  8. "json_encode": escape.json_encode,
  9. "squeeze": escape.squeeze,
  10. "linkify": escape.linkify,
  11. "datetime": datetime,
  12. }
  13.  
  14. #创建变量环境并执行函数,详细Demo见上一篇博文
  15. namespace.update(kwargs)
  16. exec self.compiled in namespace
  17. execute = namespace["_execute"]
  18.  
  19. try:
  20. #执行编译好的字符串格式的函数,获取嵌套了值的html文件
  21. return execute()
  22. except:
  23. formatted_code = _format_code(self.code).rstrip()
  24. logging.error("%s code:\n%s", self.name, formatted_code)
  25. raise

Template.generate

其中涉及的类有:

  1. class _TemplateReader(object):
  2. def __init__(self, name, text):
  3. self.name = name
  4. self.text = text
  5. self.line = 0
  6. self.pos = 0
  7.  
  8. def find(self, needle, start=0, end=None):
  9. assert start >= 0, start
  10. pos = self.pos
  11. start += pos
  12. if end is None:
  13. index = self.text.find(needle, start)
  14. else:
  15. end += pos
  16. assert end >= start
  17. index = self.text.find(needle, start, end)
  18. if index != -1:
  19. index -= pos
  20. return index
  21.  
  22. def consume(self, count=None):
  23. if count is None:
  24. count = len(self.text) - self.pos
  25. newpos = self.pos + count
  26. self.line += self.text.count("\n", self.pos, newpos)
  27. s = self.text[self.pos:newpos]
  28. self.pos = newpos
  29. return s
  30.  
  31. def remaining(self):
  32. return len(self.text) - self.pos
  33.  
  34. def __len__(self):
  35. return self.remaining()
  36.  
  37. def __getitem__(self, key):
  38. if type(key) is slice:
  39. size = len(self)
  40. start, stop, step = key.indices(size)
  41. if start is None: start = self.pos
  42. else: start += self.pos
  43. if stop is not None: stop += self.pos
  44. return self.text[slice(start, stop, step)]
  45. elif key < 0:
  46. return self.text[key]
  47. else:
  48. return self.text[self.pos + key]
  49.  
  50. def __str__(self):
  51. return self.text[self.pos:]

_TemplateReader

  1. class _ChunkList(_Node):
  2. def __init__(self, chunks):
  3. self.chunks = chunks
  4.  
  5. def generate(self, writer):
  6. for chunk in self.chunks:
  7. chunk.generate(writer)
  8.  
  9. def each_child(self):
  10. return self.chunks

_ChunkList

  1. def _parse(reader, in_block=None):
  2.  
  3. #默认创建一个内容为空列表的_ChunkList对象
  4. body = _ChunkList([])
  5.  
  6. # 将html块添加到 body.chunks 列表中
  7. while True:
  8. # Find next template directive
  9. curly = 0
  10. while True:
  11. curly = reader.find("{", curly)
  12. if curly == -1 or curly + 1 == reader.remaining():
  13. # EOF
  14. if in_block:
  15. raise ParseError("Missing {%% end %%} block for %s" %in_block)
  16. body.chunks.append(_Text(reader.consume()))
  17. return body
  18. # If the first curly brace is not the start of a special token,
  19. # start searching from the character after it
  20. if reader[curly + 1] not in ("{", "%"):
  21. curly += 1
  22. continue
  23. # When there are more than 2 curlies in a row, use the
  24. # innermost ones. This is useful when generating languages
  25. # like latex where curlies are also meaningful
  26. if (curly + 2 < reader.remaining() and
  27. reader[curly + 1] == '{' and reader[curly + 2] == '{'):
  28. curly += 1
  29. continue
  30. break
  31.  
  32. # Append any text before the special token
  33. if curly > 0:
  34. body.chunks.append(_Text(reader.consume(curly)))
  35.  
  36. start_brace = reader.consume(2)
  37. line = reader.line
  38.  
  39. # Expression
  40. if start_brace == "{{":
  41. end = reader.find("}}")
  42. if end == -1 or reader.find("\n", 0, end) != -1:
  43. raise ParseError("Missing end expression }} on line %d" % line)
  44. contents = reader.consume(end).strip()
  45. reader.consume(2)
  46. if not contents:
  47. raise ParseError("Empty expression on line %d" % line)
  48. body.chunks.append(_Expression(contents))
  49. continue
  50.  
  51. # Block
  52. assert start_brace == "{%", start_brace
  53. end = reader.find("%}")
  54. if end == -1 or reader.find("\n", 0, end) != -1:
  55. raise ParseError("Missing end block %%} on line %d" % line)
  56. contents = reader.consume(end).strip()
  57. reader.consume(2)
  58. if not contents:
  59. raise ParseError("Empty block tag ({%% %%}) on line %d" % line)
  60.  
  61. operator, space, suffix = contents.partition(" ")
  62. suffix = suffix.strip()
  63.  
  64. # Intermediate ("else", "elif", etc) blocks
  65. intermediate_blocks = {
  66. "else": set(["if", "for", "while"]),
  67. "elif": set(["if"]),
  68. "except": set(["try"]),
  69. "finally": set(["try"]),
  70. }
  71. allowed_parents = intermediate_blocks.get(operator)
  72. if allowed_parents is not None:
  73. if not in_block:
  74. raise ParseError("%s outside %s block" %
  75. (operator, allowed_parents))
  76. if in_block not in allowed_parents:
  77. raise ParseError("%s block cannot be attached to %s block" % (operator, in_block))
  78. body.chunks.append(_IntermediateControlBlock(contents))
  79. continue
  80.  
  81. # End tag
  82. elif operator == "end":
  83. if not in_block:
  84. raise ParseError("Extra {%% end %%} block on line %d" % line)
  85. return body
  86.  
  87. elif operator in ("extends", "include", "set", "import", "from",
  88. "comment"):
  89. if operator == "comment":
  90. continue
  91. if operator == "extends":
  92. suffix = suffix.strip('"').strip("'")
  93. if not suffix:
  94. raise ParseError("extends missing file path on line %d" % line)
  95. block = _ExtendsBlock(suffix)
  96. elif operator in ("import", "from"):
  97. if not suffix:
  98. raise ParseError("import missing statement on line %d" % line)
  99. block = _Statement(contents)
  100. elif operator == "include":
  101. suffix = suffix.strip('"').strip("'")
  102. if not suffix:
  103. raise ParseError("include missing file path on line %d" % line)
  104. block = _IncludeBlock(suffix, reader)
  105. elif operator == "set":
  106. if not suffix:
  107. raise ParseError("set missing statement on line %d" % line)
  108. block = _Statement(suffix)
  109. body.chunks.append(block)
  110. continue
  111.  
  112. elif operator in ("apply", "block", "try", "if", "for", "while"):
  113. # parse inner body recursively
  114. block_body = _parse(reader, operator)
  115. if operator == "apply":
  116. if not suffix:
  117. raise ParseError("apply missing method name on line %d" % line)
  118. block = _ApplyBlock(suffix, block_body)
  119. elif operator == "block":
  120. if not suffix:
  121. raise ParseError("block missing name on line %d" % line)
  122. block = _NamedBlock(suffix, block_body)
  123. else:
  124. block = _ControlBlock(contents, block_body)
  125. body.chunks.append(block)
  126. continue
  127.  
  128. else:
  129. raise ParseError("unknown operator: %r" % operator)

_parse

  1. class Template(object):
  2.  
  3. def _generate_python(self, loader, compress_whitespace):
  4. buffer = cStringIO.StringIO()
  5. try:
  6. named_blocks = {}
  7. ancestors = self._get_ancestors(loader)
  8. ancestors.reverse()
  9. for ancestor in ancestors:
  10. ancestor.find_named_blocks(loader, named_blocks)
  11. self.file.find_named_blocks(loader, named_blocks)
  12. writer = _CodeWriter(buffer, named_blocks, loader, self,
  13. compress_whitespace)
  14. ancestors[0].generate(writer)
  15. return buffer.getvalue()
  16. finally:
  17. buffer.close()

Template._generate_python

so,上述整个过程其实就是将一个html转换成一个函数,并为该函数提供全局变量,然后执行该函数!!

结束语

上述就是对于模板语言的整个流程,其本质就是处理html文件内容将html文件内容转换成函数,然后为该函数提供全局变量环境(即:我们想要嵌套进html中的值和框架自带的值),再之后执行该函数从而获取到处理后的结果,再再之后则执行UI_Modules继续丰富返回结果,例如:添加js文件、添加js内容块、添加css文件、添加css内容块、在body内容第一行插入数据、在body内容最后一样插入数据,最终,通过soekct客户端对象将处理之后的返回结果(字符串)响应给请求用户。

Python框架之Tornado (源码之褪去模板外衣)的更多相关文章

  1. 第四篇:白话tornado源码之褪去模板外衣的前戏

    加班程序员最辛苦,来张图醒醒脑吧! ... ... ... 好了,醒醒吧,回归现实看代码了!! 执行字符串表示的函数,并为该函数提供全局变量 本篇的内容从题目中就可以看出来,就是为之后剖析tornad ...

  2. Python框架之Tornado(四)源码之褪去模板外衣

    上一篇介绍了客户端请求在tornado框架中的生命周期,其本质就是利用epoll和socket来获取并处理请求.在上一篇的内容中,我们只是给客户端返回了简单的字符串,如:“Hello World”,而 ...

  3. 第五篇:白话tornado源码之褪去模板的外衣

    上一篇<白话tornado源码之请求来了>介绍了客户端请求在tornado框架中的生命周期,其本质就是利用epoll和socket来获取并处理请求.在上一篇的内容中,我们只是给客户端返回了 ...

  4. Python框架之Tornado(四)源码之褪去模板外衣的前戏

    执行字符串表示的函数,并为该函数提供全局变量 本篇的内容从题目中就可以看出来,就是为之后剖析tornado模板做准备,也是由于该知识点使用的巧妙,所有就单独用一篇来介绍了.废话不多说,直接上代码: # ...

  5. Python框架之Tornado(源码之褪去模板外衣的前戏)

    执行字符串表示的函数,并为该函数提供全局变量 本篇的内容从题目中就可以看出来,就是为之后剖析tornado模板做准备,也是由于该知识点使用的巧妙,所有就单独用一篇来介绍了.废话不多说,直接上代码: # ...

  6. 第三篇:白话tornado源码之请求来了

    上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...

  7. 第二篇:白话tornado源码之待请求阶段

    上篇<白话tornado源码之一个脚本引发的血案>用上帝视角多整个框架做了一个概述,同时也看清了web框架的的本质,下面我们从tornado程序的起始来分析其源码. 概述 上图是torna ...

  8. 04: 打开tornado源码剖析处理过程

    目录:Tornado其他篇 01: tornado基础篇 02: tornado进阶篇 03: 自定义异步非阻塞tornado框架 04: 打开tornado源码剖析处理过程 目录: 1.1 torn ...

  9. Python框架之Tornado(概述)

    本系列博文计划: 1.剖析基于Python的Web框架Tornado的源码,为何要阅读源码? Tornado 由前 google 员工开发,代码非常精练,实现也很轻巧,加上清晰的注释和丰富的 demo ...

随机推荐

  1. Centos7安装Apache Http服务器无法访问如何解决

    1. 安装Apache组件 [root@mycentos shell]# yum install httpd 2. 安装成功后,检测有无httpd进程 [root@mycentos shell]# p ...

  2. html 调用ActiveX

    html网页调用ActiveX控件时,要获取到ActiveX的ClassID,这个ClassID是注册到系统里的,而不是工程中的uuid,(下图为uuid). 正确的是在注册表的HKEY_CLASSE ...

  3. ubuntu16.04主题美化和软件推荐(转载)

    从这里转载!转载!转载! http://blog.csdn.net/terence1212/article/details/52270210

  4. .Net framework 的浏览器定义文件

    .net framework4.5.1之前的版本有一个非常愚蠢的设定, 它为每个浏览器设置了一个浏览器定义文件, 通过正则表达式来匹配浏览器的userAgent, 然后来定义一些功能集. 这种做法有一 ...

  5. quartz定时任务配置

    参考:http://www.cnblogs.com/kay/archive/2007/11/02/947372.html Quartz是一个强大的企业级任务调度框架,Spring中继承并简化了Quar ...

  6. Html5-Canvas 与 SVG 的比较

    Canvas 与 SVG 的比较 Canvas 依赖分辨率 不支持事件处理器 弱的文本渲染能力 能够以 .png 或 .jpg 格式保存结果图像 最适合图像密集型的游戏,其中的许多对象会被频繁重绘 S ...

  7. 【谷歌浏览器】在任意页面运行JS

    1.使用谷歌浏览器的调试功能: 在任何页面上运行代码片段 · Chrome 开发者工具中文文档 注:比较简单,直接,不过只能本地执行,只能自己使用.且需自行保存JS文件: 2.使用油猴插件: Tamp ...

  8. Jupyter Notebook远程服务器配置

    首先要生成密码,打开python终端. In [1]: from IPython.lib import passwd In [2]: passwd() Enter password: Verify p ...

  9. 观《phonegap第三季 angularjs+ionic视频教程 实时发布》学习笔记(三)

    十五.ionic路由 1.ionic中内联模板介绍 使用内联模板内联模板的使用,常见的有几种情况.(1) 使用ng-include指令可以利用ng-include指令在HTML中直接使用内联模板,例如 ...

  10. 几种常见数据库查询判断表和字段是否存在sql

    1.MSSQL Server    表:select COUNT(*) from dbo.sysobjectsWHEREname= 'table_name':  字段:select COUNT(*)  ...