列位看官曾記否?在[《玩轉字符串(1)》](https://github.com/qiwsir/ITArticles/blob/master/BasicPython/107.md)中,有專門講到了有關“轉義”問題,就是在python的字符串中,有的符號要想表達其本意,需要在前面加上`\`符號,例如單引號,如果要在字符串中表現它,必須寫成`\'單引號里面\'`樣式,才能實現一對單引號以及里面的內容,否則,它就表示字符串了。
在HTML代碼中,也有類似的問題,比如`>`等,就是代碼的一部分,如果直接寫,就不會顯示在網頁里,要向顯示,同樣需要轉義。另外,如果在網頁中有表單,總會有別有用心的人向表單中寫點包含`>`等字符的東西,目的就是要攻擊你的網站,為了防治邪惡之輩,也需要將用戶輸入的字符進行轉義,轉化為字符實體,讓它不具有HTML代碼的含義。
> 轉義字符串(Escape Sequence)也稱字符實體(Character Entity)。在HTML中,定義轉義字符串的原因有兩個:第一個原因是像“”這類符號已經用來表示HTML標簽,因此就不能直接當作文本中的符號來使用。為了在HTML文檔中使用這些符號,就需要定義它的轉義字符串。當解釋程序遇到這類字符串時就把它解釋為真實的字符。在輸入轉義字符串時,要嚴格遵守字母大小寫的規則。第二個原因是,有些字符在ASCII字符集中沒有定義,因此需要使用轉義字符串來表示。
## 模板自動轉義
Tornado 2 開始的模板具有自動轉義的功能,這讓開發者省卻了不少事情。看一個例子。就利用上一講中建立的開發框架。要在首頁模板中增加一個表單提交功能。
修改template/index.html文件,內容如下:
~~~
<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 "qiwsir@gmail.com" in info %}
<p><b>A Ha, this the python lesson of LaoQi, 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>
~~~
在增加的表單中,要將內容以`post`方法提交到`"/option"`,所以,要在url.py中設置路徑,并且要建立相應的類。
然后就在handler目錄中建立一個新的文件,命名為optform.py,其內容就是一個類,用來接收index.html中`post`過來的表單內容。
~~~
#!/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'的表單內容
self.render("info.html",web=website)
~~~
為了達到接收表單post到上述類中內容的目的,還需要對url.py進行如下改寫:
~~~
#!/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中,當接收到來自表單內容之后,就用另外一個模板`info.html`顯示所接收到的內容。這個文件放在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>
~~~
這樣我們就完成表單內容的提交和顯示過程。
從上面的流程中,看官是否體驗到這個框架的優勢了?不用重復敲代碼,只需要在框架內的不同地方增加內容,即可完成網站。
演示運行效果:
我在表單中輸入了`alert('bad script')`,這是多么陰險毒辣呀。
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/31401.png)
然而我們的tornado是不懼怕這種攻擊的,因為它的模板自動轉義了。當點擊按鈕提交內容的時候,就將那些陰險的符號實體化,成為轉義之后的符號了。于是就這樣了:
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/31402.png)
輸入什么,就顯示什么,不會因為輸入的內容含有陰險毒辣的符號而網站無法正常工作。這就是轉義的功勞。
## 不轉義的辦法
在tornado中,模板實現了自動轉義,省卻了開發者很多事,但是,事情往往沒有十全十美的,這里省事了,一定要在別的地方費事。例如在上面那個info.html文件中,我打算在里面加入我的電子信箱,但是要像下面代碼這樣,設置一個變量,主要是為了以后修改方便和在其它地方也可以隨意使用。
~~~
<DOCTYPE html>
<html>
...(省略)
<body>
<h1>My Website is:</h1>
<p>{{web}}</p>
{% set email="<a href='mailto:qiwsir@gmail.com'>Connect to me</a>"%}
<p>{{email}}</p>
</body>
</html>
~~~
本來希望在頁面中出現的是`Connect to me`,點擊它之后,就直接連接到發送電子郵件。結果,由于轉義,出現的是下面的顯示結果:
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/31403.png)
實現電子郵件超鏈接未遂。
這時候,就需要不讓模板轉義。tornado提供的方法是:
* 在Application函數實例化的時候,設置參數:autoescape=None。這種方法不推薦適應,因為這樣就讓全站模板都不轉意了,看官愿意嘗試,不妨進行修改試一試,我這里就不展示了。
* 在每個頁面中設置{% autoescape None %},表示這個頁面不轉義。也不推薦。理由,自己琢磨。
* 以上都不推薦,我推薦的是:{% raw email %},想讓哪里不轉義,就在那里用這種方式,比如要在email超級鏈接那里不轉移,就寫成這樣好了。于是修改上面的代碼,看結果為:
[](https://github.com/qiwsir/ITArticles/blob/master/Pictures/31404.png)
如此,實現了不轉義。
以上都實現了模板的轉義和不轉義。
## url轉義
本來模板轉義和不轉義問題已經交代清楚了。怎奈上周六一個朋友問了一個問題,那個問題涉及到url轉義問題,于是在這里再補上一段,專門談談url轉義的問題。
有些符號在URL中是不能直接傳遞的,如果要在URL中傳遞這些特殊符號,那么就要使用它們的編碼了。編碼的格式為:%加字符的ASCII碼,即一個百分號%,后面跟對應字符的ASCII(16進制)碼值。例如 空格的編碼值是"%20"。
在python中,如果用utf-8寫了一段地址,如何轉義成url能夠接收的字符呢?
在python中有一個urllib模塊:
~~~
>>> import urllib
>>> #假設下面的url,是utf-8編碼
>>> url_mail='http://www.itdiffer.com/email?=qiwsir@gmail.com'
>>> #轉義為url能夠接受的
>>> urllib.quote(url_mail)
'http%3A//www.itdiffer.com/email%3F%3Dqiwsir%40gmail.com'
~~~
反過來,一個url也能轉移為utf-8編碼格式,請用urllib.unquote()
下面抄錄幫助文檔中的內容,供用到的朋友參考:
~~~
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'
~~~
轉義是網站開發中要特別注意的地方,不小心或者忘記了,就會糾結。
- 第零部分 獨上高樓,望盡天涯路
- 嘮叨一些關于Python的事情
- 為什么要開設本欄目
- 第一部分 積小流,至江海
- Python環境安裝
- 集成開發環境(IDE)
- 數的類型和四則運算
- 啰嗦的除法
- 開始真正編程
- 初識永遠強大的函數
- 玩轉字符串(1):基本概念、字符轉義、字符串連接、變量與字符串關系
- 玩轉字符串(2)
- 玩轉字符串(3)
- 眼花繚亂的運算符
- 從if開始語句的征程
- 一個免費的實驗室
- 有容乃大的list(1)
- 有容乃大的list(2)
- 有容乃大的list(3)
- 有容乃大的list(4)
- list和str比較
- 畫圈還不簡單嗎
- 再深點,更懂list
- 字典,你還記得嗎?
- 字典的操作方法
- 有點簡約的元組
- 一二三,集合了
- 集合的關系
- Python數據類型總結
- 深入變量和引用對象
- 賦值,簡單也不簡單
- 坑爹的字符編碼
- 做一個小游戲
- 不要紅頭文件(1): open, write, close
- 不要紅頭文件(2): os.stat, closed, mode, read, readlines, readline
- 第二部分 窮千里目,上一層樓
- 正規地說一句話
- print能干的事情
- 從格式化表達式到方法
- 復習if語句
- 用while來循環
- 難以想象的for
- 關于循環的小伎倆
- 讓人歡喜讓人憂的迭代
- 大話題小函數(1)
- 大話題小函數(2)
- python文檔
- 重回函數
- 變量和參數
- 總結參數的傳遞
- 傳說中的函數條規
- 關于類的基本認識
- 編寫類之一創建實例
- 編寫類之二方法
- 編寫類之三子類
- 編寫類之四再論繼承
- 命名空間
- 類的細節
- Import 模塊
- 模塊的加載
- 私有和專有
- 折騰一下目錄: os.path.<attribute>
- 第三部分 昨夜西風,亭臺誰登
- 網站的結構:網站組成、MySQL數據庫的安裝和配置、MySQL的運行
- 通過Python連接數據庫:安裝python-MySQLdb,連接MySQL
- 用Pyton操作數據庫(1):建立連接和游標,并insert and commit
- 用Python操作數據庫(2)
- 用Python操作數據庫(3)
- python開發框架:框架介紹、Tornado安裝
- Hello,第一個網頁分析:tornado網站的基本結構剖析:improt模塊、RequestHandler, HTTPServer, Application, IOLoop
- 實例分析get和post:get()通過URL得到數據和post()通過get_argument()獲取數據
- 問候世界:利用GAE建立tornado框架網站
- 使用表單和模板:tornado模板self.render和模板變量傳遞
- 模板中的語法:tornado模板中的for,if,set等語法
- 靜態文件以及一個項目框架
- 模板轉義
- 第四部分 暮然回首,燈火闌珊處
- requests庫
- 比較json/dictionary的庫
- defaultdict 模塊和 namedtuple 模塊
- 第五部分 Python備忘錄
- 基本的(字面量)值
- 運算符
- 常用的內建函數
- 擴展閱讀(來自網絡文章)
- 人生苦短,我用Python