在python的字符串中,有的符號(hào)要想表達(dá)其本意,需要在前面加上\符號(hào),例如單引號(hào),如果要在字符串中表現(xiàn)它,必須寫(xiě)成\'單引號(hào)里面\'樣式,才能實(shí)現(xiàn)一對(duì)單引號(hào)以及里面的內(nèi)容,否則,它就表示字符串了。
在HTML代碼中,也有類似的問(wèn)題,比如>等,就是代碼的一部分,如果直接寫(xiě),就不會(huì)顯示在網(wǎng)頁(yè)里,要想顯示,同樣需要轉(zhuǎn)義。另外,如果在網(wǎng)頁(yè)中有表單,總會(huì)有別有用心的人向表單中寫(xiě)點(diǎn)包含>等字符的東西,目的就是要攻擊你的網(wǎng)站,為了防治邪惡之輩,也需要將用戶輸入的字符進(jìn)行轉(zhuǎn)義,轉(zhuǎn)化為字符實(shí)體,讓它不具有HTML代碼的含義。
轉(zhuǎn)義字符串(Escape Sequence)也稱字符實(shí)體(Character Entity)。在HTML中,定義轉(zhuǎn)義字符串的原因有兩個(gè):第一個(gè)原因是像“<”和“>”這類符號(hào)已經(jīng)用來(lái)表示HTML標(biāo)簽,因此就不能直接當(dāng)作文本中的符號(hào)來(lái)使用。為了在HTML文檔中使用這些符號(hào),就需要定義它的轉(zhuǎn)義字符串。當(dāng)解釋程序遇到這類字符串時(shí)就把它解釋為真實(shí)的字符。在輸入轉(zhuǎn)義字符串時(shí),要嚴(yán)格遵守字母大小寫(xiě)的規(guī)則。第二個(gè)原因是,有些字符在ASCII字符集中沒(méi)有定義,因此需要使用轉(zhuǎn)義字符串來(lái)表示。
模板自動(dòng)轉(zhuǎn)義
Tornado 2 開(kāi)始的模板具有自動(dòng)轉(zhuǎn)義的功能,這讓開(kāi)發(fā)者省卻了不少事情。看一個(gè)例子。就利用上一講中建立的開(kāi)發(fā)框架。要在首頁(yè)模板中增加一個(gè)表單提交功能。
修改template/index.html文件,內(nèi)容如下:
<DOCTYPE html>
<html>
<head>
<title>Loop in template</title>
<link rel="stylesheet" type="text/css" href="{{ static_url('css/style.css')}}">
</head>
<body>
<h1>aaaAAA</h1>
<p>There is a list, it is <b>{{info}}</b></p>
<p>I will print the elements of this list in order.</p>
{% for element in info %}
<p>{{element}}</p>
{% end %}
<br>
{% for index,element in enumerate(info) %}
<p>info[{{index}}] is {{element}}
{% if element == "python" %}
<p> <b>I love this language--{{element}}</b></p>
{% end %}
{% end %}
{% if "hiekay@gmail.com" in info %}
<p><b>A Ha, this the python lesson of hiekay, It is good! His email is {{info[2]}}</b></p>
{% end %}
<h2>Next, I set "python-tornado"(a string) to a variable(var)</h2>
{% set var="python-tornado" %}
<p>Would you like {{var}}?</p>
<!--增加表單-->
<form method="post" action="/option">
<p>WebSite:<input id="website" name="website" type="text"></p>
<p><input type="submit" value="ok,submit"></p>
</form>
</body>
</html>
在增加的表單中,要將內(nèi)容以post方法提交到"/option",所以,要在url.py中設(shè)置路徑,并且要建立相應(yīng)的類。
然后就在handler目錄中建立一個(gè)新的文件,命名為optform.py,其內(nèi)容就是一個(gè)類,用來(lái)接收index.html中post過(guò)來(lái)的表單內(nèi)容。
#!/usr/bin/env python
#coding:utf-8
import tornado.web
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
class OptionForm(tornado.web.RequestHandler):
def post(self):
website = self.get_argument("website") #接收名稱為'website'的表單內(nèi)容
self.render("info.html",web=website)
為了達(dá)到接收表單post到上述類中內(nèi)容的目的,還需要對(duì)url.py進(jìn)行如下改寫(xiě):
#!/usr/bin/env python
#coding:utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from handler.index import IndexHandler
from handler.optform import OptionForm
url=[
(r'/', IndexHandler),
(r'/option', OptionForm),
]
還要注意,我在新建立的optform.py中,當(dāng)接收到來(lái)自表單內(nèi)容之后,就用另外一個(gè)模板info.html顯示所接收到的內(nèi)容。這個(gè)文件放在template目錄中,代碼是:
<DOCTYPE html>
<html>
<head>
<title>Loop in template</title>
<link rel="stylesheet" type="text/css" href="{{ static_url('css/style.css')}}">
</head>
<body>
<h1>My Website is:</h1>
<p>{{web}}</p>
</body>
</html>
這樣我們就完成表單內(nèi)容的提交和顯示過(guò)程。
從上面的流程中,是否體驗(yàn)到這個(gè)框架的優(yōu)勢(shì)了?不用重復(fù)敲代碼,只需要在框架內(nèi)的不同地方增加內(nèi)容,即可完成網(wǎng)站。
演示運(yùn)行效果:
我在表單中輸入了<script>alert('bad script')</script>,這是多么陰險(xiǎn)毒辣呀。

然而我們的tornado是不懼怕這種攻擊的,因?yàn)樗哪0遄詣?dòng)轉(zhuǎn)義了。當(dāng)點(diǎn)擊按鈕提交內(nèi)容的時(shí)候,就將那些陰險(xiǎn)的符號(hào)實(shí)體化,成為轉(zhuǎn)義之后的符號(hào)了。于是就這樣了:

輸入什么,就顯示什么,不會(huì)因?yàn)檩斎氲膬?nèi)容含有陰險(xiǎn)毒辣的符號(hào)而網(wǎng)站無(wú)法正常工作。這就是轉(zhuǎn)義的功勞。
不轉(zhuǎn)義的辦法
在tornado中,模板實(shí)現(xiàn)了自動(dòng)轉(zhuǎn)義,省卻了開(kāi)發(fā)者很多事,但是,事情往往沒(méi)有十全十美的,這里省事了,一定要在別的地方費(fèi)事。例如在上面那個(gè)info.html文件中,我打算在里面加入我的電子信箱,但是要像下面代碼這樣,設(shè)置一個(gè)變量,主要是為了以后修改方便和在其它地方也可以隨意使用。
<DOCTYPE html>
<html>
...(省略)
<body>
<h1>My Website is:</h1>
<p>{{web}}</p>
{% set email="<a href='mailto:hiekay@gmail.com'>Connect to me</a>"%}
<p>{{email}}</p>
</body>
</html>
本來(lái)希望在頁(yè)面中出現(xiàn)的是Connect to me,點(diǎn)擊它之后,就直接連接到發(fā)送電子郵件。結(jié)果,由于轉(zhuǎn)義,出現(xiàn)的是下面的顯示結(jié)果:

實(shí)現(xiàn)電子郵件超鏈接未遂。
這時(shí)候,就需要不讓模板轉(zhuǎn)義。tornado提供的方法是:
- 在Application函數(shù)實(shí)例化的時(shí)候,設(shè)置參數(shù):autoescape=None。這種方法不推薦使用,因?yàn)檫@樣就讓全站模板都不轉(zhuǎn)義了,愿意嘗試,不妨進(jìn)行修改試一試,我這里就不展示了。
- 在每個(gè)頁(yè)面中設(shè)置{% autoescape None %},表示這個(gè)頁(yè)面不轉(zhuǎn)義。也不推薦。
- 以上都不推薦,我推薦的是:{% raw email %},想讓哪里不轉(zhuǎn)義,就在那里用這種方式,比如要在email超級(jí)鏈接那里不轉(zhuǎn)移,就寫(xiě)成這樣好了。于是修改上面的代碼,看結(jié)果為:
<DOCTYPE html>
<html>
<head>
<title>Loop in template</title>
<link rel="stylesheet" type="text/css" href="{{ static_url('css/style.css')}}">
</head>
<body>
<h1>My Website is:</h1>
<p>{{web}}</p>
{%raw email="<a href='mailto:hiekay@gmail.com'>Connect to me</a>"%}
</body>
</html>

如此,實(shí)現(xiàn)了不轉(zhuǎn)義。
以上都實(shí)現(xiàn)了模板的轉(zhuǎn)義和不轉(zhuǎn)義。
url轉(zhuǎn)義
有些符號(hào)在URL中是不能直接傳遞的,如果要在URL中傳遞這些特殊符號(hào),那么就要使用它們的編碼了。編碼的格式為:%加字符的ASCII碼,即一個(gè)百分號(hào)%,后面跟對(duì)應(yīng)字符的ASCII(16進(jìn)制)碼值。例如 空格的編碼值是"%20"。
在python中,如果用utf-8寫(xiě)了一段地址,如何轉(zhuǎn)義成url能夠接收的字符呢?
在python中有一個(gè)urllib模塊:
>>> import urllib
>>> #假設(shè)下面的url,是utf-8編碼
>>> url_mail='http://www.hiekay.com/email?=hiekay@gmail.com'
>>> #轉(zhuǎn)義為url能夠接受的
>>> urllib.quote(url_mail)
'http%3A//www.hiekay.com/email%3F%3Dhiekay%40gmail.com'
#反過(guò)來(lái),一個(gè)url也能轉(zhuǎn)移為utf-8編碼格式,請(qǐng)用urllib.unquote()
>>>urllib.unquote('http%3A//www.hiekay.com/email%3F%3Dhiekay%40gmail.com')
'http://www.hiekay.com/email?=hiekay@gmail.com'
下面抄錄幫助文檔中的內(nèi)容,供用到的朋友參考:
quote(s, safe='/')
quote('abc def') -> 'abc%20def'
Each part of a URL, e.g. the path info, the query, etc., has a
different set of reserved characters that must be quoted.
RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
the following reserved characters.
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
"$" | ","
Each of these characters is reserved in some component of a URL,
but not necessarily in all of them.
By default, the quote function is intended for quoting the path
section of a URL. Thus, it will not encode '/'. This character
is reserved, but in typical usage the quote function is being
called on a path where the existing slash characters are used as
reserved characters.
unquote(s)
unquote('abc%20def') -> 'abc def'.
quote_plus(s, safe='')
Quote the query fragment of a URL; replacing ' ' with '+'
unquote_plus(s)
unquote('%7e/abc+def') -> '~/abc def'
轉(zhuǎn)義是網(wǎng)站開(kāi)發(fā)中要特別注意的地方,不小心或者忘記了,就會(huì)糾結(jié)。