17 Web开发

CS/BS

  • CS Client/Server
  • BS Browser/Server
  • 浏览器只不过是一种特殊的客户端
    • 使用HTTP(s)协议
    • 解析渲染HTML
  • BS开发分类 :
    • 客户端开发/前端开发 HTML CSS JavaScript
    • 服务器开发/后端开发 Python使用WSGI Django Flask Tornado

HTTP

  • HTTP是无状态协议
    • 同一客户端的两次请求之间没有任何关系
    • 服务器无法分辨两个请求是否来自同一浏览器

cookies

  • 键值对信息,用于解决HTTP协议无状态的问题
  • 浏览器每次向发起请求,都会携带cookies信息
  • 服务器可通过判断cookies,来确定不同得请求之间是否有关联
  • cookies信息一般由服务器生成 返回给浏览器,但浏览器也可以自己设置cookies信息

URL

  • Uniform Resource Locator 统一资源定位符 简而言之就是地址
  • 格式如下

    schema://host[:port]/path/.../[:url-params][?query-string][#anchor]
  • 例如 :
https://cn.bing.com/search?q=python&qs=n&form=QBRE
  • http协议默认80端口
  • https协议默认443端口
  • /path/to/resource 指向资源路径
  • ?q=python&qs=n&form=QBRE query String 查询字符串 问好分割 后面的key=value形式,用&分割

无状态 有连接 短连接

  • 无状态 : 服务器无法分辨两个请求是否来自同一浏览器
  • 有连接 : HTTP基于TCP,是面向连接的,需要三次握手,四次断开
  • 短连接 :
    • HTTP1.1之前,一个请求一个连接 但TCP连接的创建和销毁成本太高,对服务器有很大影响
    • HTTP1.1开始支持keep-alive,一个链接打开后会保持一段时间,减轻了服务器的压力

WSGI

Created with Raphaël 2.1.2 浏览器 浏览器 WSGI Server WSGI Server WSGI App WSGI App HTTP 请求 解包,封装environ 调用App 逻辑处理 HTTP状态码 报文头 返回正文 HTTP正文

相关参考 : http://python.jobbole.com/87361/

wsgiref库

from wsgiref.simple_server import make_server


def app(environ,start_response):
    qstr=environ.get('QUERY_STRING')
    qd={k:v for k,_,v in map(lambda x:x.partition('='),qstr.split('&'))}

    print(123,qstr,'\n',456,qd)
    status='200 OK'
    headers=[('Content-Type','text/html;charset=utf-8')]
    start_response(status,headers)
    res = '<h1>中文Test Page</h1>'.encode()
    return [res]
#app要求可调用,传两个参数,返回一个可迭代对象

ip='127.0.0.1'
port=80
server=make_server(ip,port,app)
server.serve_forever()
----------------------------------------------------------------------
浏览器访问http://127.0.0.1/?a=1&b=2&a=3&123=456&fg=中文,jk
服务器端输出信息 :
123 a=1&b=2&a=3&123=456&fg=%E4%B8%AD%E6%96%87,jk 
127.0.0.1 - - [26/Jun/2018 10:55:18] "GET /?a=1&b=2&a=3&123=456&fg=%E4%B8%AD%E6%96%87,jk HTTP/1.1" 200 24
 456 {'a': '3', 'b': '2', '123': '456', 'fg': '%E4%B8%AD%E6%96%87,jk'}

urllib库 : 解析url查询字符串

from urllib import parse
qstr='a=1&b=2&a=3&123=456&fg=中文,jk'
qd=parse.parse_qs(qstr)
print(123,qstr,'\n',456,qd)
-----------------------------------
123 a=1&b=2&a=3&123=456&fg=中文,jk 
 456 {'a': ['1', '3'], 'b': ['2'], '123': ['456'], 'fg': ['中文,jk']}

webob库

  • environ数据保存在字典中,不方便操作
  • 使用webob库可将environ数据转化为request对象
  • 用Request解析environ :
from wsgiref.simple_server import make_server
from webob import Request

def app(environ,start_response):

    r=Request(environ)
    print('r.headers : {}\nr.method : {}\nr.path : {}\nr.query_string : {}\nr.GET : {}\nr.POST : {}\nr.params : {}'.format(
        r.headers,
        r.method,
        r.path,
        r.query_string,
        r.GET,
        r.POST,
        r.params))
    status='200 OK'
    headers=[('Content-Type','text/html;charset=utf-8')]
    start_response(status,headers)
    res = '<h1>中文Test Page</h1>'.encode()
    return [res]

ip='127.0.0.1'
port=80
server=make_server(ip, port,app)
server.serve_forever()
--------------------------------------------------------------------
浏览器访问http://127.0.0.1/?a=1&b=2&a=3&123=456&fg=中文,jk
服务器端输出信息 :
r.headers : <webob.headers.EnvironHeaders object at 0x0000021244A96748>
r.method : GET
r.path : /
r.query_string : a=1&b=2&a=3&123=456&fg=%E4%B8%AD%E6%96%87,jk
r.GET : GET([('a', '1'), ('b', '2'), ('a', '3'), ('123', '456'), ('fg', '中文,jk')])
r.POST : <NoVars: Not an HTML form submission (Content-Type: text/plain)>
r.params : NestedMultiDict([('a', '1'), ('b', '2'), ('a', '3'), ('123', '456'), ('fg', '中文,jk')])
127.0.0.1 - - [26/Jun/2018 11:33:39] "GET /?a=1&b=2&a=3&123=456&fg=%E4%B8%AD%E6%96%87,jk HTTP/1.1" 200 24
r.headers : <webob.headers.EnvironHeaders object at 0x0000021244A968D0>
r.method : GET
r.path : /favicon.ico
r.query_string : 
r.GET : GET([])
r.POST : <NoVars: Not an HTML form submission (Content-Type: text/plain)>
r.params : NestedMultiDict([])
127.0.0.1 - - [26/Jun/2018 11:33:39] "GET /favicon.ico HTTP/1.1" 200 24
  • MultiDict :
from webob.multidict import MultiDict
md=MultiDict()
md.add('1', 'value')
md.add('1', 'value2')#add函数可以形成一键多值
md['2']='123'#建索引赋值和update会将多值变为单值,
md['2']='234'
md['a']='123asd'
md['b']='bn'
md.add('b', 'value')
md.add('b', 'value2')
print("md : {}\nmd.getall('1') : {}\nmd.get('b') : {}\nmd.getone('a') : {}".format(md,md.getall('1'),md.get('b'),md.getone('a')))
for k,v in md.items():
    print('k: {},v: {}'.format(k,v))
--------------------------------------------------------------------
md : MultiDict([('1', 'value'), ('1', 'value2'), ('2', '234'), ('a', '123asd'), ('b', 'bn'), ('b', 'value'), ('b', 'value2')])
md.getall('1') : ['value', 'value2'] #返回列表
md.get('b') : value2
md.getone('a') : 123asd #要求键值'a'有且只能有一个值,否则会报错
k: 1,v: value
k: 1,v: value2
k: 2,v: 234
k: a,v: 123asd
k: b,v: bn
k: b,v: value
k: b,v: value2
  • Response :
from wsgiref.simple_server import make_server
from webob import Response,Request


def app(environ:dict,start_response):
    req=Request(environ)
    res=Response()
    res.status_code=200
    print(res.content_type,'\n',res.status,'\n',res.headerlist)
    html = '<h1>中文Test Page</h1>'.encode()
    res.body=html
    return res(environ, start_response)

ip='127.0.0.1'
port=80,
server=make_server(ip, port,app)
server.serve_forever()
--------------------------------------------------------------------
text/html 
 200 OK 
 [('Content-Type', 'text/html; charset=UTF-8'), ('Content-Length', '0')]
127.0.0.1 - - [26/Jun/2018 15:52:03] "GET /?a=1&b=2&a=3&123=456&fg=%E4%B8%AD%E6%96%87,jk HTTP/1.1" 200 24
text/html 
 200 OK 
 [('Content-Type', 'text/html; charset=UTF-8'), ('Content-Length', '0')]
127.0.0.1 - - [26/Jun/2018 15:52:03] "GET /favicon.ico HTTP/1.1" 200 24

wsgify装饰器 :

  • 该装饰器装饰的函数要求有一个参数,此参数为webob.Request类型,且是对字典environ的对象化后的实例
  • 返回值是webob.Response类型,若为str或bytes类,会经过str–>bytes–>Response的转化
from wsgiref.simple_server import make_server
from webob import Request,Response
from webob.dec import wsgify


@wsgify
def app(request:Request)->Response:
    res=Response('<h1>中文测试Test Page</h1>')
    return res

ip='127.0.0.1'
port=80
server=make_server(ip, port,app)
server.serve_forever()

路由

  • URL路径与处理函数(或静态文件)的映射
  • 使用字典,key为path,value为handle函数
  • 为更好地匹配url路径.引入正则表达式,key由静态的path改为正则匹配模式pattern
  • 考虑到匹配顺序问题,将字典换为二元组(compiled(pattern),handle)
  • 再次细分 可将浏览器请求方法也加入
from wsgiref.simple_server import make_server
from webob import Response,Request
from webob.dec import wsgify
from webob.exc import HTTPNotFound
import re
# from functools import partialmethod


#小技巧,字典属性化
class AttrDict:
    def __init__(self,d):
        self.__dict__.update(d if isinstance(d,dict) else {})

    def __setattr__(self):
        raise NotImplementedError


class Router:
    ##ROUTETABLE每一项是由 请求方法 编译过的正则表达式 与处理函数组成 
    #(method,compilde_pattern,handle)
    ROUTETABLE=[]
    #注册路由,装饰器更新ROUTETABLE名单
    @classmethod
    def route(cls,method,pattern):
        def wrapper(handler):
            cls.ROUTETABLE.append( (method.upper(),re.compile(pattern),handler))
            return handler
        return wrapper
    # get = partialmethod(route,'GET')

    @classmethod
    def get(cls,pattern):
        return cls.route('GET',pattern)

    @classmethod
    def post(cls,pattern):
        return cls.route('POST',pattern)

    @classmethod
    def head(cls,pattern):
        return cls.route('HEAD',pattern)

@Router.get(r'^/$') #匹配网站根目录
@Router.route('GET',r'^/(?P<id>\d+)$') #匹配数字
def indexhandle(request:Request):
    print(request.groups,request.groupdict,sep='\n')
    # return Response('<h1>Welcome to Index Page id={}</h1>'.format(request.groupdict.get('id',0)))
    r= AttrDict(request.groupdict)
    id = r.id if hasattr(r, 'id') else ''
    return Response('<h1>Welcome to Index Page id={}</h1>'.format(id))

@Router.get(r'^/python$')
def pythonhandler(request:Request):
    res=Response()
    # res.charset='utf-8'
    res.body='<h1>Welcome to Python Page</h1>'.encode()
    return res



class App:

    _Router=Router

    @wsgify
    def __call__(self,request:Request):
        for method,pattern,handler in self._Router.ROUTETABLE:
            #not method表示未指定请求方法,则支持全部方法
            if not method or request.method.upper() in method:
                matcher=pattern.match(request.path)
                if matcher:
                     request.groups=matcher.groups()
                    request.groupdict=matcher.groupdict()
                    return handler(request)
        raise HTTPNotFound('<h1>404</h1>')


if __name__ == '__main__':

    ip='127.0.0.1'
    port=80
    server=make_server(ip, port, App())

    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.shutdown()
        server.server_close()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值