web框架详解之tornado 三 url和分页

一、代码目录构建

controllers  :处理业务逻辑的

account:处理账户相关的

上面目录作用和内容

controllers 包 :处理业务逻辑的

         account:处理账户相关的

         home是主页内容文件

settings   包:内容设置等

         Setting:配置文件

statics    包: 静态文件的下相关目录

views     包: HTML文件包

内容分别为:

#/usr/bin/env python
#-*-coding:utf-8 -*-
import tornado.web

class LoginHandler(tornado.web.RequestHandler):
    def get(self,*args,**kwargs):
        self.write("ok")
class LogoutHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        self.write("ok")
class RegisterHandler(tornado.web.RedirectHandler):
    def get(self,*args,**kwargs):
        self.write("ok")
account文件
#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web


class IndexHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        # self.write("index.html")
        self.render("index.html")
home文件
#/usr/bin/env python
#-*-coding:utf-8-*-

settings={
    "template_path":"views",#模板路径的配置
    "static_path":"statics" #静态文件
}
Setting文件
#/bin/usr/env python
#-*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from controllers import home
from settings import Setting

#路由映射,路由系统
application=tornado.web.Application(
    [(r"/index",home.IndexHandler),],
    **Setting.settings
)

if __name__=="__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()
start文件

其实就是把tornado拆解了

#!/usr/bin/env python
# -*- coding:utf-8 -*-

# 首先导入模块
import tornado.ioloop
import tornado.web
# 让这个类继承   执行
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("s1.html")
# 路由映射,也可以叫做路由系统
application = tornado.web.Application([
    (r"/index", MainHandler),
])
if __name__ == "__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()
View Code

二、基于正则的动态路由

设置分页:在路由系统中,用正则匹配数字,并且让第一个明明为num,第二个为nid

#路由映射,路由系统
application=tornado.web.Application(
    [(r"/index/(?P<num>\d*)/(?P<nid>\d*)",home.IndexHandler),],
    **Setting.settings
)
#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web


class IndexHandler(tornado.web.RequestHandler):
    def get(self,nid,num):
        # self.write("index.html")
        print(nid,num)
        self.render("index.html")
在home文件中设置

在网页url中输入http://127.0.0.1:8000/index/12321/151

 

在后台中输出 151 和12321

 三、路由系统之二级域名

application.add_handlers("www.cnblogs.com",[
    (r"/index/(?P<page>\d*)",这里是自己定义的类)
])
View Code

二级路由就是:首先匹配域名,然后再匹配域名下的各个页面

一级路由是直接匹配各个页面

四、自定义分页:

redirect_to实现的是action方法的跳转,向浏览器发起一个新的请求,具体使用方法如下

注意点:用户连接tornado的时候,这个框架会用get方法给服务端发送页面信息,然后客户端向服务端发送消息,这里是用post方式,从客户端发送消息到服务端
View Code
#/bin/usr/env python
#-*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from controllers import home
from settings import Setting

#路由映射,路由系统
application=tornado.web.Application(
    [(r"/index/(?P<page>\d*)",home.IndexHandler),],
    **Setting.settings
)

if __name__=="__main__":
    application.listen(8000)
    tornado.ioloop.IOLoop.instance().start()
start代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>提交数据</h1>
<form method="post" action="/index/1">
    <input name="username" type="text"/>
    <input name="email" type="text"/>
    <input type="submit" value="提交"/>
</form>
<h1>显示数据</h1>
    <table border="1">
        <thead>
        <tr>
            <th>用户名</th>
            <th>邮箱</th>
        </tr>
        </thead>
        <tbody>
        {% for line in list_info %}
            <tr>
                <td>{{line['username']}}</td>
                <td>{{line['email']}}</td>
            </tr>
        {% end %}
        </tbody>
    </table>
</body>
</html>
HTML代码
#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web

LIST_INFO=[
    {"username":"aa","email":"pyrene3110436742@162.com"}
]
class IndexHandler(tornado.web.RequestHandler):
    def get(self,page):
        #假如每页显示5条数据
        # page是当前页
        # 第一页:05   LIST_INFO[0:5]
        #第二页:5:10    LIST_INFO[5:10]
        try:
            page=int(page)
        except Exception:
            page=1
        if page<1:
            page=1
        start=(page-1)*5
        end=page*5
        current_list=LIST_INFO[start:end]

        # print(nid,num)
        self.render("home/index.html" ,list_info=current_list)
    def post(self, *args, **kwargs):
        user=self.get_argument("username")
        email=self.get_argument("email")
        temp={"username":user,"email":email}
        LIST_INFO.append(temp)
        self.redirect("/index/1")
home代码

分析:

这里有两种内容

1、用户通过表格form提交数据,通过post方法,把输入的内容添加到LIST_INFO列表中,并且通过redirect方法跳转到get方法中返回给客户端

2、内部做了页面判断,并且让页面只显示5条数据,用户通过路由系统输入url来访问每一页

自定义分页优化

通过传值来记住当前页

三中的bug问题点在于:页面输入的时候,会跳转到首页,要解决

 

#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web

LIST_INFO=[
    {"username":"aa","email":"pyrene3110436742@162.com"}
]
class IndexHandler(tornado.web.RequestHandler):
    def get(self,page):
        #假如每页显示5条数据
        # page是当前页
        # 第一页:05   LIST_INFO[0:5]
        #第二页:5:10    LIST_INFO[5:10]
        try:
            page=int(page)
        except Exception:
            page=1
        if page<1:
            page=1
        start=(page-1)*5
        end=page*5
        current_list=LIST_INFO[start:end]

        # print(nid,num)
        self.render("home/index.html" ,list_info=current_list,current_page=page)
    def post(self,page):
        user=self.get_argument("username")
        email=self.get_argument("email")
        temp={"username":user,"email":email}
        LIST_INFO.append(temp)
        self.redirect("/index/"+page)
home代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>提交数据</h1>
<form method="post" action="/index/{{current_page}}">
    <input name="username" type="text"/>
    <input name="email" type="text"/>
    <input type="submit" value="提交"/>
</form>
<h1>显示数据</h1>
    <table border="1">
        <thead>
        <tr>
            <th>用户名</th>
            <th>邮箱</th>
        </tr>
        </thead>
        <tbody>
        {% for line in list_info %}
            <tr>
                <td>{{line['username']}}</td>
                <td>{{line['email']}}</td>
            </tr>
        {% end %}
        </tbody>
    </table>
</body>
</html>
index代码

后台get方法中自定义页码变量,传入到html中,之后用户输入触发post方法,然后在post方法中跳转到当前页面

自定义分页二:实现下图中的分页

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pager a{
            display: inline-block;
            padding: 5px;
            margin: 3px;
            background-color: cadetblue;
        }
        .pager a.active{
            background-color:brown ;
            color: white;
        }
    </style>
</head>
<body>
<h1>提交数据</h1>
<form method="post" action="/index/{{current_page}}">
    <input name="username" type="text"/>
    <input name="email" type="text"/>
    <input type="submit" value="提交"/>
</form>
<h1>显示数据</h1>
    <table border="1">
        <thead>
        <tr>
            <th>用户名</th>
            <th>邮箱</th>
        </tr>
        </thead>
        <tbody>
        {% for line in list_info %}
            <tr>
                <!--<td>{{line['username']}}</td>-->
                <td>{% raw line['username']%}</td>
                <td>{{line['email']}}</td>
            </tr>
        {% end %}
        </tbody>
    </table>
<div class="pager">
        {% raw str_page %}
</div>
</body>
</html>
HTML代码
#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web

LIST_INFO=[
    {"username":"aa","email":"pyrene3110436742@162.com"}
]
for i in range(99):
    temp={"username":"bb"+str(i),"email":str(i)+"123"}
    LIST_INFO.append(temp)
class IndexHandler(tornado.web.RequestHandler):
    def get(self,page):
        #假如每页显示5条数据
        # page是当前页
        # 第一页:05   LIST_INFO[0:5]
        #第二页:5:10    LIST_INFO[5:10]
        try:
            page=int(page)
        except Exception:
            page=1
        if page<1:
            page=1
        start=(page-1)*5
        end=page*5
        current_list=LIST_INFO[start:end]

        all_pager,c=divmod(len(LIST_INFO),5)
        if c>0:
            all_pager+=1

        list_page=[]

        for p in range(all_pager):
            # 设置当前页的样式
            if p+1 ==page:
                temp='<a class="active" href="/index/%s">%s</a>' %(p+1,p+1)
            else:
                temp='<a href="/index/%s">%s</a>'%(p+1,p+1)
            list_page.append(temp)

        str_page="".join(list_page)

        # print(nid,num)
        self.render("home/index.html" ,list_info=current_list,current_page=page,str_page=str_page)
python代码
 1 实现步骤:
 2 首先在后台计算出数据的总页数,用divemode的方法 
 3 all_pager,c=divmod(len(LIST_INFO),5)
 4 if c>0:
 5     all_pager+=1
 6 all_pager为整数,c为小数,这里判断,如果c为小数的时候让整数加上1,也就是需要显示的页数
 7 2、创建一个空列表,并且遍历计算出来的页数,返回给前端页面
 8 list_page=[]
 9 
10 for p in range(all_pager):
11     # 设置当前页的样式
12     if p+1 ==page:
13         temp='<a class="active" href="/index/%s">%s</a>' %(p+1,p+1)
14     else:
15         temp='<a href="/index/%s">%s</a>'%(p+1,p+1)
16     list_page.append(temp)
17 
18 str_page="".join(list_page)
19 
20 # print(nid,num)
21 self.render("home/index.html" ,list_info=current_list,current_page=page,str_page=str_page)
22 注意点:
23 1、这里要设置点击到那一页的时候就显示那一页的样式,用于区分
24 2、由于要传给前台的是字符串,所以这里要用join方法分割成字符串
25 3、pag参数为当前页码
26 
27 前台代码:
28 <div class="pager">
29         {% raw str_page %}
30 </div>
31 由于后台传过来的数据,要按照后台的样式展示给用户,所以这里要用原声的js显示
32 这里注意,后台要显示的原生的js必须是指定范围的,不然会被攻击

自定义分页优化

 优化如下:

具体思想如下:

all_pager:总页数
current_pager:当前页
# range(当前页-5,当前页+5+1)
当  总页数<11的时候
1、    显示总页数
当  总页数>11的时候
 如果当前页<=6:
    显示前11页
  如果当前页>6:
如果:当前页+5 >总页数:
    总页数 -11  , 总页数
else:
    当前页-5, 当前页+5
View Code
#s t 分页逻辑,这里让其显示11条信息
        if all_pager<11:
            s=1
            t=all_pager
        else:
            if page<=6:
                s=1
                t=11
            else:
                if(page+5)>all_pager:
                    s=all_pager-10
                    t=all_pager
                else:
                    s=page-5
                    t=page+5

        #注意这里的p代表的是s和t+1之间的页码
        for p in range(s,t+1):
            # 设置当前页的样式
            if p ==page:
                temp='<a class="active" href="/index/%s">%s</a>' %(p,p)
            else:
                temp='<a href="/index/%s">%s</a>'%(p,p)
            list_page.append(temp)

        str_page="".join(list_page)
python代码实现

如何做成插件?

 

把各个方法分别封装到类中,然后如果以后想用这个插件,直接导入这个插件中的类就可以


如果要封装页码:需要思考需求和产出什么
需求:总页数、当前页
产出:start  end  str_page

把方法封装到类中,类中分别对应方法
#/usr/bin/env python
#-*-coding:utf-8-*-
import tornado.web

LIST_INFO=[
    {"username":"aa","email":"pyrene3110436742@162.com"}
]
for i in range(99):
    temp={"username":"bb"+str(i),"email":str(i)+"123"}
    LIST_INFO.append(temp)

class Pagination:
    #下面封装的参数分别为,当前页数,和总的数据
    def __init__(self,current_page,all_item):   #初始化当前页和总页数
        all_pager,c=divmod(all_item,5)   #all_pager为计算的到的总页数,要经过下面的判断
        if c>0:
            all_pager+=1
        self.all_pager=all_pager

        try:                                    #为当前页处理异常
            current_page=int(current_page)
        except Exception:
            current_page=1
        if current_page<1:
            current_page=1
        self.current_page=current_page


    # 加上这样的装饰器,会使下面调用这个方法的时候以访问字段的形式来访问,也就是不用加上括号
    @property
    def start(self):                        #当前页的起始数据
        return (self.current_page-1)*5
    @property
    def end(self):                          #当前页的结尾数据
        return self.current_page*5

    def page_str(self,base_url):            # 生成页码逻辑
        list_page=[]
        if self.all_pager<11:
            s=1
            t=self.all_pager
        else:
            if self.current_page<=6:
                s=1
                t=11
            else:
                if( self.current_page+5)>self.all_pager:
                    s=self. current_page-10
                    t=self. current_page
                else:
                    s= self.current_page-5
                    t= self.current_page+5
        for p in range(s,t+1):
            if p == self.current_page:
                temp='<a class="active" href="%s%s">%s</a>' %(base_url,p,p) #这里设置自定义url
            else:
                temp='<a href="%s%s">%s</a>'%(base_url,p,p)
            list_page.append(temp)

        return "".join(list_page)                       #直接返回值


class IndexHandler(tornado.web.RequestHandler):
    def get(self,page):

        page_obj=Pagination(page,len(LIST_INFO))                    #传入当前页和总页数生成对象
        current_list=LIST_INFO[page_obj.start:page_obj.end]        #以字段的方式来应用类中的方法
        str_page=page_obj.page_str("/index/")                       #传入自己自定义的url

        # 传入参数,当前页的参数和页码数的参数
        self.render("home/index.html" ,list_info=current_list,current_page=page_obj.current_page,str_page=str_page)


    def post(self,page):
        user=self.get_argument("username")
        email=self.get_argument("email")
        temp={"username":user,"email":email}
        LIST_INFO.append(temp)
        self.redirect("/index/"+page)
python代码

跳转页面

1 location.href=”url”
2 首页:尾页:上一页:下一页都不难
3 
4 搜索跳转的代码形式:
5 只要执行上面的就会自动跳转到指定的url
6 所以这里用了js的事件方法,只不过把js变成字符串的形式传递给前台,然后转化为js代码的形式
#首页
first_page='<a  href="%s1">首页</a>'%(base_url,)
list_page.append(first_page)

#上一页 current_page-1 在javascript中加上javascript:void(0)表示什么也不做
if self.current_page==1:
    pre_page='<a href="javascript:void(0)">上一页</a>'
else:
    pre_page='<a  href="%s%s">上一页</a>'%(base_url,self.current_page-1)
list_page.append(pre_page)

    #中间页数
for p in range(s,t+1):
    if p == self.current_page:
        temp='<a class="active" href="%s%s">%s</a>' %(base_url,p,p) #这里设置自定义url
    else:
        temp='<a class-"active" href="%s%s">%s</a>'%(base_url,p,p)
    list_page.append(temp)
#尾页
last_page='<a  href=%s%s>尾页</a>'%(base_url,self.all_pager)
list_page.append(last_page)

#下一页 current_page+1 在javascript中加上javascript:void(0)表示什么也不做
if self.current_page>=self.all_pager:
    next_page='<a href="javascript:void(0)">下一页</a>'
else:
    next_page='<a  href="%s%s">下一页</a>'%(base_url,self.current_page+1)
list_page.append(next_page)

#跳转页面
jump='''<input type="text" /><a  onclick="jump('%s',this);">GO</a>'''%(base_url,)
script='''<script>
function jump(baseUrl,ths){
    var val=ths.previousElementSibling.value;
    if(val.trim().length>0){
        location.href=baseUrl+val
    }
}
</script>'''
list_page.append(jump)
list_page.append(script)
return "".join(list_page) 
View Code

五、安全XSS攻击

xss跨站脚本攻击

 

 1 <h1>显示数据</h1>
 2     <table border="1">
 3         <thead>
 4         <tr>
 5             <th>用户名</th>
 6             <th>邮箱</th>
 7         </tr>
 8         </thead>
 9         <tbody>
10         {% for line in list_info %}
11             <tr>
12                 <!--<td>{{line['username']}}</td>-->
13                 <td>{% raw line['username']%}</td>
14                 <td>{{line['email']}}</td>
15             </tr>
16         {% end %}
17         </tbody>
18     </table>

上面13行的就是以原始方式展示,没做处理,那么无论用户还是后台输入的js代码都会以js形式展示给用户

这种就是xss跨站脚本攻击模式

 

posted @ 2017-04-07 05:41  pyrene  阅读(440)  评论(0编辑  收藏  举报