一、Web开发

Tcp   udp

 
   

Cs即客户端、服务器端编程,客户端和服务器端之间需要使用socket,约定协议、版本(协议使用的是tcp或者udp)。Tcp协议和udp协议,指定地址和端口,就可以通信了。

客户端、服务器端传输数据,数据可以有一定的格式,双方必须先约定好。

1、BS

Bs:在tcp协议之上的http协议开发的,浏览器和服务器,是基于cs开发之上的。

Browser、server开发

Browser浏览器,一种特殊的客户端,支持HTTP(s)协议,能够通过URL向服务器端发起请求,等待服务端返回HTML,并在浏览器内可视化展示的程序。

server,支持HTTP(s)协议,能够介绍众多客户端发起的HTTP协议请求,经过处理,将HTML等数据返回给浏览器。

是特殊的cs,即客户端必须是一种支持HTTP协议且能解析并渲染HTML的软件,服务器端必须是能够接受多客户端http访问的软件服务器。

http协议底层是基于tcp协议实现的。

2、分类

客户器端开发:HTML,css,Javascript

服务器端开发:Python有wsgi,Django,flask,tornado。

3、HTTP协议

1)简介

安装httpd

#yum install httpd

HTTP协议是无状态协议。

同一个客户端的两次请求之间没有任何关系,从服务器端角度来说,不知道两个请求是来自同一个客户端。

2)cookie

键值对信息,浏览器发起每一请求,都会把cookie信息发给服务器端,是一种客户端、服务器端传递数据的技术。

服务器端可以通过判断这些信息,来确定这次请求是否和之前的请求有关联,

一般来说cookie信息是在服务器端生成的,返回给客户端。

客户端可以自己设置cookie信息。

3)URL

URL就是地址,统一资源定位符uniform resource locator。每一个连接指向一个资源供客户端访问。

URL组成:方言,host,path路径,查询字符串。

访问静态资源的时候,通过URL访问的是网站某路径下的index.html文件,而这个文件对应磁盘上的真实文件,就会从磁盘上读取这个文件, 把这个文件发回给浏览器。

Scheme模式、协议:

http、ftp、https、file、mailto等等,都是类似

host:port

www.xxxx.com:80默认端口80不写,域名会使用dns解析,

/path/to.resource

Path,指向资源的路径。

?key1=value&key2=value2

Query string,查询字符串,问号分割,后面的可以=value形式,用&符号分割。

4、HTTP消息

消息分为request和response

Request:浏览器向服务器端发起请求。

Response:服务器对客户端的请求响应。

请求和响应的消息都由请求行,header消息报头,body消息正文组成。

1)请求

(1)请求消息行:请求方法method、请求路径、协议版本、CRLF(回车换行)。Get  /  http
/1.1

(2)请求方法method

Get:请求获取对应URL对应的资源。把请求的内容到放到了header的里面。

Post:提交数据至服务器端,请求报文头部。

Head:和get相似,不过不返回消息正文。

(3)常见传递信息的方式

使用get方法使用querystring

通过查询字符串在URL中传递参数。

Post方法提交数据。

URL本身就包含着信息

2)响应

响应消息行:协议版本,状态码,消息描述CRLF(回车换行)。    http/1.1 
200 ok

状态码在响应第一行:

1xx:提示信息,表示请求已被成功接收,继续处理。

2xx:表示正常响应。

200.正常的返回了网页消息

3xx:重定向

301
页面永久移走,永久重定向,返回新的URL,浏览器会根据返回的URL发起新的request请求。

302
临时重定向

304资源未修改,浏览器使用本地缓存。

4xx:客户端请求错误

404
not found 网页找不到,客户端请求的资源有错误。

400  请求语法错误

401
请求要求身份验证

403服务器拒绝请求。

5xx:服务器端错误

500
服务器内部错误

502上游服务器错误

5、无状态、有连接和短连接

无状态:服务器不知道两次连接请求的之间的关系,同一个浏览器两次访问,服务器端不知道两次之间是有联系的。后来可以根据cookie,session判断。

有连接:基于tcp协议,是面向连接的,需要3次握手,4次挥手。

短连接:http1.1之前,都是一个请求一个连接,而tcp的连接创建销毁成本太高,对服务器影响很大。

从http1.1开始,支持keep-live。默认开启,一个连接打开后,会保持一段时间(可以设置),浏览器再次访问该服务器就会使用这个tcp连接,减轻了服务器的压力,提高了效率。

6、wsgi

Wsgi 服务器的通用网关接口。基于http协议的server。

Wsgi主要规定了服务器端和应用程序间的接口

Python
Web Server Gateway Interface

通用网关接口cgi

(1)重点

基于http协议,wsgi app和server之间的应用。

对应的函数进行处理。

不同的路径代表不同的请求。函数和请求之间的映射关系。

框架对应URL,

Server把处理逻辑提出去,提给app

浏览器发送请求给server,server把请求头解包,封装成为字典,调用wsgi的app,app进行逻辑处理,处理完毕后直接返回状态码和报文头给浏览器,返回正文到wsgi到server,server发送http协议正文给浏览器。

from wsgiref.util import setup_testing_defaults

from wsgiref.simple_server import make_server

# A relatively simple WSGI application. It's going to
print out the

# environment dictionary after being updated by
setup_testing_defaults

def simple_app(environ, start_response):

setup_testing_defaults(environ)

status = '200
OK'

headers =
[('Content-type', 'text/plain; charset=utf-8')]

start_response(status, headers)  #返回正文之间必须先返回状态码

ret =
[("%s: %s\n" % (key, value)).encode("utf-8")

for key,
value in environ.items()]

return ret

httpd = make_server('', 8000, simple_app)

print("Serving on port 8000...")

httpd.serve_forever()

7、wsgi服务器 ----wsgiref

Wsgiref.simple_server模块实现简单的wsgi http服务器端。

Wsgiref.Simple_server. make_server(ip,port,demo_app,server_class=wsgisercer,handler_class=wsgirequesthandler)

启动一个wsgi服务器。

Wsgiref.simple_server.demo_app(environ,start_response)一个函数,完成了wsgi的应用程序端。

###简单的服务器端代码:

from wsgiref.simple_server import make_server,demo_app



ip = '127.0.0.1'

port = 9999

server = make_server(ip,port,demo_app)# demo_app应用程序,可调用

server.serve_forever()

Wsgi服务器的作用:

监听HTTP服务端口(tcpserver,默认端口80)

接受浏览器端的HTTP请求并解析封装成environ环境数据。

负责调用应用程序,将environ和start_response方法传入。

将应用程序响应的正文封装成http响应报文返回浏览器端。

8、wsgi app应用程序端

1)应用程序应该是一个可调用对象。

2)这个可调用对象接收两个参数。

3)可调用对象,返回的是一个可迭代对象。函数和class__call__返回值是[]  class中__init__ 要有yield.

def application(environ,start_response):

    pass



class Application:

    def __init__(self,environ,start_response):

        pass

def __iter__(self):

        yield self.ret



class Application:

    def __call__(self, environ,start_response):

        pass

app程序端三种实现:

from wsgiref.simple_server import make_server,demo_app



#

def application(environ,start_response):

    status = '200 ok'

    headers = [('Content-Type','text/html;charset=utf-8')]

    start_response(status,headers)

    ret_sre1 = b'welcome to this '

    ret_sre = '{}'.format('welcome').encode()

    return [ret_sre]



class Application:

    def __init__(self,environ,start_response):

        status = '200 ok'

        headers = [('Content-Type', 'text/html;charset=utf-8')]

        start_response(status, headers)

        ret_sre1 = b'welcome to this '

        # ret_sre = '{}'.format('welcome').encode()

        self.ret
= ret_sre1

    def __iter__(self):

        yield self.ret



#

class Application:

    def __call__(self, environ,start_response):

        status = '200 ok'

        headers = [('Content-Type', 'text/html;charset=utf-8')]

        start_response(status, headers)

        ret_sre1 = b'welcome to this '

        # ret_sre = '{}'.format('welcome').encode()

        return [ret_sre1]

ip = '127.0.0.1'

port = 9999

server = make_server(ip,port,Application())# demo_app应用程序,可调用

server.serve_forever()

8、environ

是包含HTTP请求信息的dict对象

名称

含义

REQUEST_METHOD

请求方法,get、post等

PATH_INFO

URL中的路径部分

QUERY_STRING

查询字符串

SERVER_NAME,SERVER_POST

服务器名、端口

HTTP_HOST

地址和端口

SERVER_PROTOCOL

协议

HTTP_USER_AGENT

Useragent信息

9、start_response

是一个可调用对象,有3个参数,

Status:状态码和描述语。

Response_headers:可迭代对象,是一个元素为二元组的列表。[('Content-Type',
'text/html;charset=utf-8')]    响应头部

Exc_info=None:在错误处理的时候使用.

start_reaponse 应该在返回可迭代对象之前调用,因为其返回的是response
header,返回的可迭代对象是response
body。

10、服务器端

服务器程序需要调用符合上述定义的可调用对象app,传入environ、start_response,app处理后,返回响应头和可迭代对象的正文,由服务器封装返回浏览器端。

from wsgiref.simple_server import make_server



def application(*args):

    environ = args[0]

    start_response = args[1]

    for k,v in environ.items():

        print(k,v)

    print('====================')

    status = '200 ok'

    headers = [('Content-Type', 'text/html;charset=utf-8')]

    start_response(status,headers)

    ret = [("%s :%s\n" % (key,value)).encode('utf-8') for key,value
in environ.items()]

    return ret



ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,application)

server.serve_forever()

测试命令:curl  -I 使用head方法。

curl   -X 指定方法,-d传输数据

11、Web服务器

本质上就是一个tcp协议,监听在特定的端口上

支持HTTP协议,能够将HTTP请求的报文进行解析,能够把响应数据进行HTTP协议的报文封装并返回浏览器。

实现wsgi协议,协议约定了和应用程序之间接口。

HTTP协议是应用层。

12、app应用程序

遵从wagi协议

本身是一个可调用对象

调用start_response,返回响应头部。

返回包含正文的可迭代对象。

响应的是调用app的调用,response的是status,headers。

app的两个参数environ和start_response

二、flask框架的实现

1、wsgi请求environment处理

Wsgi服务器会帮忙处理http请求报文,但是提供的environ是一个用起来很不方便的字典。

2、query_string查询字符串的解析

from wsgiref.simple_server import make_server



#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    print(query_string)

    #1字典

    # d = {}

    # for item in
query_string.split('&'):

    #    
k,_,v  = item.partition('=')

    #    
d[k] = v

    #    
print('k={},v={}'.format(k,v))

    #    
print(d)

    #2字典解析式

    d = {k:v for k,_,v in map(lambda
item:item.partition('='),query_string.split('&'))}

    print(d)

    status = '200 ok'

    headers = [('Content-Type', 'text/html;charset=utf-8')]

    start_response(status,headers)



   
ret = 'welcome to {}'.format('item').encode()

    return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

name=tome&age=3&age=2

127.0.0.1 - - [26/Jun/2018 16:40:14]
"POST /xxx?name=tome&age=3&age=2 HTTP/1.1" 200 15

{'name': 'tome', 'age': '2'}

3、cgi模块查询

import cgi



from wsgiref.simple_server import make_server



#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    print(query_string)

    #1字典

    # d = {}

    # for item in query_string.split('&'):

    #    
k,_,v  = item.partition('=')

    #    
d[k] = v

    #    
print('k={},v={}'.format(k,v))

    #    
print(d)

    #2字典解析式

    # d = {k:v for k,_,v in map(lambda
item:item.partition('='),query_string.split('&'))}

    # print(d)

    qs = cgi.parse_qs(query_string)

    print(qs)

    status = '200 ok'

    headers = [('Content-Type', 'text/html;charset=utf-8')]

    start_response(status,headers)



    ret = 'welcome to {}'.format('item').encode()

    return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

name=tome&age=3&age=2

127.0.0.1 - - [26/Jun/2018 17:19:06]
"POST /xxx?name=tome&age=3&age=2 HTTP/1.1" 200 15

{'age': ['3', '2'], 'name': ['tome']}

Cgi模块value的值是列表,因为value可以有多个值。

3、urllib库

urllib:请求解析重要的库。

多值是age=1&age=2这个是多值。

age=1,2只是一个值。

Parse_se函数,将同一个名称的多值,保存在字典中,使用列表保存。

import cgi

from urllib.parse import parse_qs

from wsgiref.simple_server import make_server



#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    print(query_string)

    #1字典

    # d = {}

    # for item in query_string.split('&'):

    #     k,_,v  = item.partition('=')

    #     d[k] = v

    #     print('k={},v={}'.format(k,v))

    #     print(d)

    #2字典解析式

    # d = {k:v for k,_,v in map(lambda item:item.partition('='),query_string.split('&'))}

    # print(d)

    # qs = cgi.parse_qs(query_string)

    # print(qs)

    qs = parse_qs(query_string)

    print(qs)

    status = '200 ok'

    headers = [('Content-Type', 'text/html;charset=utf-8')]

    start_response(status,headers)



    ret = 'welcome to {}'.format('item').encode()

    return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

name=tome&age=3&age=2

{'age': ['3', '2'], 'name': ['tome']}

127.0.0.1 - - [26/Jun/2018 17:28:24] "POST /xxx?name=tome&age=3&age=2 HTTP/1.1" 200 15

name=tome&age=3&age=2,3

{'age': ['3', '2,3'], 'name': ['tome']}

4、webob库

环境数据有很多,都是存在字典中,字典的存取方式没有对象的属性访问方便。

利用第三方库webob库,可以把环境数据的解析、封装成为类。

1)webob简介

安装pip install webob

官方文档:https://docs.pylonsproject.org/projects/webob/en/stable/#webob

2)webob.request对象

from wsgiref.simple_server import make_server

import webob

#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    #print(query_string)

    request = webob.Request(environ)

    print(1,request.headers)

    print(2,request.method)

    print(3,request.path)

    print(4,request.query_string)

    print(5,request.GET)

    print(6,request.POST)

    print('params={}'.format(request.params))



    status = '200 ok'

    headers = [('Content-Type', 'text/html;charset=utf-8')]

    start_response(status,headers)



    ret = 'welcome to {}'.format('item').encode()

    return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

1 <webob.headers.EnvironHeaders object
at 0x00000050EDB88F60>

2 POST

3 /xxx

4 name=tome&age=3&age=2,3

5 GET([('name', 'tome'), ('age', '3'),
('age', '2,3')])

6 <NoVars: Not an HTML form submission
(Content-Type: text/plain)>

params=NestedMultiDict([('name', 'tome'),
('age', '3'), ('age', '2,3')])

127.0.0.1 - - [26/Jun/2018 17:46:55]
"POST /xxx?name=tome&age=3&age=2,3 HTTP/1.1" 200 15

3)multidict

是允许一个key存多个值
的类型

from webob.multidict import MultiDict

md = MultiDict()



md.add(1,'abc')

md.add(1,'cde')

md.add('a',1)

md.add('a',2)

for pair in md.items():

    print(pair)



print(md.getall(1))

print(md.get('a'))

print(md.get(1))

(1, 'abc')

(1, 'cde')

('a', 1)

('a', 2)

['abc', 'cde']

2

Cde

4)webob.response对象

from wsgiref.simple_server import make_server

import webob

#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    #print(query_string)

    request = webob.Request(environ)

    print(1,request.headers)

    print(2,request.method)

    print(3,request.path)

    print(4,request.query_string)

    print(5,request.GET)

    print(6,request.POST)

    print('params={}'.format(request.params))



    res = webob.Response()

    # res.status_code
= 250

    # print(res.content_type)



    # print(res.status)

    # print(res.headerlist)

    # status = '200 ok'

    # headers = [('Content-Type',
'text/html;charset=utf-8')]

    # start_response(status,headers)

    start_response(res.status,res.headerlist)



    ret = 'welcome to {}'.format('item').encode('utf-8')

    # res.body = ret

    # return res(environ,start_response)

    return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

from wsgiref.simple_server import make_server

import webob

#name=tome&age=3

def simple_app(environ,start_response):

    query_string = environ.get('QUERY_STRING')

    #print(query_string)

    request = webob.Request(environ)

    print(1,request.headers)

    print(2,request.method)

    print(3,request.path)

    print(4,request.query_string)

    print(5,request.GET)

    print(6,request.POST)

    print('params={}'.format(request.params))



    res = webob.Response()       #[('Content-Type',
'text/html;charset=utf-8')]  

    res.status_code = 250      #自己可以设置属性

    print(res.content_type)



    #
print(res.status)

    # print(res.headerlist)

    # status = '200 ok'

    # headers = [('Content-Type',
'text/html;charset=utf-8')]

    # start_response(status,headers)

    # start_response(res.status,res.headerlist)



    ret = 'welcome
to {}'.format('item').encode('utf-8')

    res.body = ret

    return res(environ,start_response)   返回res

    # return [ret]





ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,simple_app)

server.serve_forever()

5)webob.dec装饰器类型

Wsgify装饰器

https://docs.pylonsproject.org/projects/webob/en/stable/api/dec.html

from webob.dec import wsgify

import webob

from wsgiref.simple_server import make_server



@wsgify

def app(request:webob.Request):

    res = webob.Response('welcome to item')

    return res



ip = '127.0.0.1'

port = 9000



server = make_server(ip,port,app)

server.serve_forever()

wsgify装饰器装饰的函数应该具有一个参数,这个参数应该是webob。Request类型,是对字典environ的对象化后的实例。

返回值:

是一个webob. Response 类型实例。

可以是一个bytes类型实例,会被封装成webob.
Response类型实例的body属性。

可以是一个字符串型实例,会被封装转换为bytes类型实例,然后会被封装成为webob. Response类型实例的body属性。

都会被封装成webob.Response

一个请求,一个响应:

from webob.dec import wsgify

import webob

from wsgiref.simple_server import make_server



@wsgify

def app(request:webob.Request):

    res = webob.Response('welcome to item')

    return res



def application(environ,start_response):

    request =
webob.Request(environ)

    res = webob.Response()

    res.status_code = 200

   
ret = 'welcome'.encode('utd-8')

    res.body = ret

    return res(environ,start_response)



if __name__ == '__main__':



    ip = '127.0.0.1'

    port = 9000



    server = make_server(ip,port,app)

    try:

        server.serve_forever()

    except Exception
as e:

        print(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

封装成类

from webob import Response,Request

from webob.dec import
wsgify

from wsgiref.simple_server import make_server



class App:

    @wsgify

    def __call__(self,request:Request):

        return 'welcome
to'



if __name__ == '__main__':

    ip = '127.0.0.1'

    port = 9000

    server = make_server(ip,port,App())

    try:

        server.serve_forever()

    except Exception
as e:

        print(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

三、类flask框架实现

Restfull:request.post

1、路由route简介

路由:路怎么走,按照不同的路径分发数据。

URL代表对不同的资源的访问,认为请求不同的路径对应的数据。对动态网页,不同的路径对应不同的应用程序来处理,返回数据,用户以为是访问的静态网页。

不管是静态web还是动态web服务器,都需要路径和资源或处理程序的映射,最终返回HTML的文本。

静态web服务器,解决路径和文件之间的映射。

动态web服务器,解决路径和应用程序之间的映射。

所有框架都是如此,都是由路由配置。

路由的映射关系。

from webob.dec import wsgify

from wsgiref import
simple_server

from webob import
Request,Response

import logging





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)









def indexhandler(request):

    return '<h1></h1>'



def pythonhandler(request):

    return '<h2></h2>'









class App:



    @wsgify

    def __call__(self, request:Request):

        path = request.path

        if path
== '/':

            return indexhandler(request)

        elif path
== '/python':

            return pythonhandler(request)



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

2、路由功能实现

路由功能,使用路由类实现。

路由类实现的功能主要就是完成path到handler函数的映射,使用字典保存合适。

理由映射建立注册方法,两个参数path和handler。

1)普通实现

from webob.dec import wsgify

from wsgiref import
simple_server

from webob import
Request,Response

import logging

from webob.exc import
HTTPNotFound



FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class Router:

    ROUTERTABLE = {}



    # @classmethod

    def register(self,path,handler):

        self.ROUTERTABLE[path]
= handler

        return handler





def indexhandler(request):

    return '<h1></h1>'



def pythonhandler(request):

    return '<h2></h2>'



router = Router()

router.register('/',indexhandler)

router.register('/python',pythonhandler)





class App:

    _Router = Router

    @wsgify

    def __call__(self, request:Request):

        path = request.path

        try:

            return self._Router.ROUTERTABLE.get(path)(request)

        except Exception
as e:

            logging.info(e)

            raise HTTPNotFound()

        # if path == '/':

        #     return indexhandler(request)

        # elif path == '/python':

        #     return pythonhandler(request)



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

2)装饰器实现

from webob.dec import wsgify

from wsgiref import
simple_server

from webob import
Response,Request

import logging

from webob.exc import
HTTPNotFound



FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)



class Router:

    ROUTERABLES = {}



    @classmethod

    def register(cls,path):

        def _register(handler):

            cls.ROUTERABLES[path] =
handler

            return handler

        return _register





@Router.register('/')

def indexhandler(request):

    return '<h1></h1>'



@Router.register('/python')

def pythonhandler(requset):

    return '<h2></h2>'



# router = Router()

# router.register('/',indexhandler)

# router.register('/python',pythonhandler)





class App:



    _Router = Router

    @wsgify

    def __call__(self, request:Request):

        path = request.path

        try:

            return self._Router.ROUTERABLES.get(path)(request)

        except Exception
as e:

            logging.info(e)

            raise HTTPNotFound()



if __name__ == '__main__':



    server = simple_server.make_server('127.0.0.1',9000,App())



    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

3、404处理

Webob.exc提供了异常模块

使用webob.exc.HTTPNoteFound表示路由表找不到对象的处理函数。

4、正则表达式匹配模式

使用字符串匹配的模式,路径匹配很死板,使用正则表达式,可以更好的匹配路径,导入re模块。注册的时候传入模式pattern。而不是字符串。

类app中实现模式和传入的路径
的匹配。

因为字典是无序的,在遍历的匹配的时候需要用到有序的,所以采用列表,列表里面的元素用二元组。(编译后的正则对象,handler)

from webob.exc import HTTPNotFound

from webob.dec import
wsgify

import logging

from webob import
Request,Response

import re

from wsgiref import
simple_server







class Router:

    ROUTERABLE = []





    @classmethod

    def register(cls,pattern):

        def _register(hanler):

            cls.ROUTERABLE.append((re.compile(pattern),hanler))

            return hanler

        return _register



@Router.register('^/$')

def indexhandler(request):

    return '<h1></h1>'



@Router.register('^python$')

def pythonhandler(request):

    return '<h2></h2>'







class App:

    _Router = Router

    @wsgify



    def __call__(self, request:Request):

        path = request.path

        for pattern,handler in self._Router.ROUTERABLE:

            if pattern.match(path):

                return handler(request)



        raise HTTPNotFound()



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

分组捕获:

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Request,Response

import re

import logging

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class Rouer:



    ROUTERABLES = []

    @classmethod

    def register(cls,pattern):

        def _register(handler):

           
cls.ROUTERABLES.append((re.compile(pattern),handler))

            return handler

        return _register



@Rouer.register('^/$')

def indexhandler(request):

    return '<h1></h1>'

@Rouer.register('^/python$')

@Rouer.register('^/python/(?P<id>\d+)$')

def pythonhandler(request):

    return '<h2></h2>{}'.format(request.groupdict)



class App:



    _Router = Rouer

    @wsgify

    def __call__(self, request:Request):

        path = request.path

        for  pattern,handler
in self._Router.ROUTERABLES:

            matcher = pattern.match(path)

            if matcher:

                request.groups =
matcher.groups()  #动态增加属性

                request.groupdict =
matcher.groupdict()

                return handler(request)

        raise HTTPNotFound()



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

5、method方法匹配

请求方法,即使是同一个URL,因为请求方法不同,处理方式也不同。

需要按照要求匹配请求方法之后才能决定执行什么函数。

方法

含义

Get

请求指定的页面信息,并返回报头和正文

HEAD

类似get请求,只不过返回的响应中没有具体内容,用于获取报头

Post

向指定的资源提交数据进行出路请求(例如提交表单或者上传文件),数据被包含在请求报文中。

Post请求客户你能会导致新的资源建立或已有的资源修改

Put

从客户端向服务器端传递的数据取代指定的文档的内容

Delete

请求服务器删除指定的内容

增加注册属性method方法。

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Request,Response

import re

import logging

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class Rouer:



    ROUTERABLES = []

    @classmethod

    def register(cls,method,pattern):

        def _register(handler):

           
cls.ROUTERABLES.append((method.upper(),re.compile(pattern),handler))

            return handler

        return _register



@Rouer.register("GET",r'^/$')

def indexhandler(request):

    return '<h1></h1>'



@Rouer.register("GET",r'^/python$')

@Rouer.register("GET",r'^/python/(?P<id>\d+)$')

def pythonhandler(request):

    return '<h2></h2>{}'.format(request.groupdict)



class App:



    _Router = Rouer

    @wsgify

    def __call__(self, request:Request):

        path = request.path

        for method, pattern,handler in self._Router.ROUTERABLES:

            if not method
== request.method.upper():

                continue

            matcher = pattern.match(path)

            if matcher:

                request.groups =
matcher.groups()

                request.groupdict =
matcher.groupdict()

                return handler(request)

        raise HTTPNotFound()



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

get的方法和post方法:

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Request,Response

import re

import logging

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class Rouer:



    ROUTERABLES = []

    @classmethod

    def register(cls,pattern,*method):

        def _register(handler):

            cls.ROUTERABLES.append((

                tuple(map(lambda
x:x.upper(),method)),

                re.compile(pattern),handler))

            print(cls.ROUTERABLES)

            return handler

        return _register



    @classmethod

    def get(cls,pattern):

        return cls.register(pattern,"GET")

    @classmethod

    def post(cls,pattern):

        return cls.register(pattern,"POST")



# @Rouer.register(r'^/$','GET')   #  1注册一个

# @Rouer.register(r'^/(?P<id>\d+)$')  
#method没有指定,支持所有的

# @Rouer.register(r'^/$')    #method没有指定,支持所有的

# @Rouer.register(r'^/$',"GET","POST")   #  1注册多个

@Rouer.get(r'/')

def indexhandler(request):

    return '<h1></h1>'



# @Rouer.register(r'^/python$','POST')   #1注册一个

#
@Rouer.register(r'^/python/(?P<id>\d+)$',"GET","HEAD")     #2注册多个get head

# # @Rouer.register(r'^/python/(?P<id>\d+)$')  #3不指定,all

@Rouer.post(r'/python')

def pythonhandler(request):

    return '<h2></h2>{}'.format(request.groupdict)



class App:



    _Router = Rouer

    @wsgify

    def __call__(self, request:Request):

        path = request.path

        for method, pattern,handler in self._Router.ROUTERABLES:

            if not method
or request.method.upper() in method:

                matcher =
pattern.match(path)

                if matcher:

                    request.groups =
matcher.groups()

                    request.groupdict =
matcher.groupdict()

                    return handler(request)

        raise HTTPNotFound()



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

map函数转换的结果是惰性求值的,利用tuple。

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Request,Response

import re

import logging

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class Rouer:



    ROUTERABLES = []

    @classmethod

    def register(cls,pattern,*method):

        def _register(handler):

            cls.ROUTERABLES.append((

                tuple(map(lambda
x:x.upper(),method)),

               
re.compile(pattern),handler))

            print(cls.ROUTERABLES)

            return handler

        return _register



# @Rouer.register(r'^/$','GET')   #  1注册一个

# @Rouer.register(r'^/(?P<id>\d+)$')  
#method没有指定,支持所有的

# @Rouer.register(r'^/$')    #method没有指定,支持所有的

@Rouer.register(r'^/$',"GET","POST")   #  1注册多个

def indexhandler(request):

    return '<h1></h1>'



# @Rouer.register(r'^/python$','POST')   #1注册一个

@Rouer.register(r'^/python/(?P<id>\d+)$',"GET","HEAD")     #2注册多个get head

# # @Rouer.register(r'^/python/(?P<id>\d+)$')  #3不指定,all



def pythonhandler(request):

    return '<h2></h2>{}'.format(request.groupdict)



class App:



    _Router = Rouer

    @wsgify

    def __call__(self, request:Request):

       
path = request.path

        for method, pattern,handler in
self._Router.ROUTERABLES:

            if not method or
request.method.upper() in method:

                matcher =
pattern.match(path)

                if matcher:

                    request.groups =
matcher.groups()

                    request.groupdict =
matcher.groupdict()

                    return handler(request)

        raise HTTPNotFound()



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

注册多个URL的method。

四、类flask框架

1、路由分组:

路由分组,就是按照前缀分别映射。

常见的一级目录:

/admin后台管理。   /product  这些目录都是根目录下的第一级。

两次注册:路由注册,和实例的注册。

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Request,Response

import logging

import re

from wsgiref import
simple_server



FORMAT = '%(asctime)s %(threadName)s
%(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)







class Router:

    def __init__(self,predix:str=''):

        self.__prefix
= predix.rstrip('/\\')  #前缀的

        self.__routables
= []  #存三元组,有序的列表



    def route_register(self,pattern,*methods):

        def _route_register(handler):

            self.__routables.append((tuple(map(lambda x:x.upper(),methods)),

                    re.compile(pattern),handler))

            return handler

        return _route_register



    def get(self,pattern):

        return self.route_register(pattern,'GET')



    def post(self,pattern):

        return self.route_register(pattern,'POST')



    def head(self,pattern):

        return self.route_register(pattern,"HEAD")



    def match(self,request:Request):

        if not request.path.startswith(self.__prefix):

            return None



        for method,patter,handler
in self.__routables:

            if not method
or request.method.upper() in method:

                matcher = patter.match(request.path.replace(self.__prefix

                                                           
,'',1))

                if matcher:

                    request.groups =
matcher.groups()

                    request.groupdict =
matcher.groupdict()

                    return handler(request)





class App:

    _ROUTES = []

    @classmethod

    def register(cls,*routers:Router):

        for router
in routers:

            cls._ROUTES.append(router)



    @wsgify

    def __call__(self,request):

        for router
in self._ROUTES:

            response =
router.match(request)

            if response:#匹配返回非None的router对象

                return response   #匹配则返回

        raise HTTPNotFound()



idx = Router()

py = Router('/python')



App.register(idx,py)





@idx.get(r'^/$')

@idx.route_register(r'^/(?P<id>\d+)$')

def indexhandler(request):

    return '<h1></h1>'



@py.get('^/(\w+)$')

@py.route_register(r'^/(?P<id>\d+)$')

def pythonhandler(request):

    return '<h2></h2>'







if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

2、字典的属性方法

属性变成字典的方式来进行访问。

让kwargs这个字典,不使用[]访问元素,而是使用.点号访问元素。如同属性一样访问。

class AttrDict:

    def __init__(self,d):

        self.__dict__.update(d)





    def __setattr__(self, key, value):

        raise NotImplementedError







d = {'a':1,'b':2}

obj = AttrDict(d)

print(obj.a)

加上属性字典:

from webob.exc import HTTPNotFound

from webob.dec import
wsgify

from webob import
Request,Response

import re

from wsgiref import
simple_server

import logging





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)



class AttrDict:

    def __init__(self,d:dict):

        self.__dict__.update(d if isinstance(d,dict)else
{})



    def __setattr__(self, key, value):

        raise NotImplementedError



    def __repr__(self):

        return '<AttrDict{}>'.format(self.__dict__)



    def __len__(self):

        return len(self.__dict__)





class Router:



    def __init__(self,prefix:str=''):

        self._prefix
= prefix.rstrip('\\/') #前缀

        self.routerables
= []   #三元组





    def router_ables(self,pattern,*methods):

        def _router_ables(handler):    #三元组

            self.routerables.append((

                tuple(map(lambda
x:x.upper(),methods)),

                re.compile(pattern),handler))

            return handler

        return _router_ables



    def get(self,pattern):

        return self.router_ables(pattern,"GET")



    def post(self,pattern):

        return self.router_ables(pattern,"POST")



    def head(self,pattern):

       
return self.router_ables(pattern,"HEAD")



    def matcher(self,request:Request):

        if not request.path.startswith(self._prefix):

            return None



        for method,pattern,handler
in self.routerables:

            if not method
or request.method.upper() in method:

                matcher =
pattern.match(request.path.replace(self._prefix,'',1))

                if matcher:
#匹配上

                    request.groups = matcher.groups()

                    request.groupdict =
AttrDict(matcher.groupdict())  #命名分组的字典被属性化

                    print(request.groupdict.id)

                    return handler(request)







class App:     #一级注册函数

    _ROUTERS = []



    @classmethod

    def app_register(cls,*routers:Router):

        for router
in routers:

            cls._ROUTERS.append(router)



    @wsgify

    def __call__(self, request:Request):

        for router
in self._ROUTERS:

            response =
router.matcher(request)  #前缀匹配

            if response:

                return response   #匹配上返回,没返回直接报错404

        raise HTTPNotFound()







idx = Router()

py = Router('/python')



App.app_register(idx,py)



@idx.get(r'^/$')

@idx.router_ables(r'^/(?P<id>\d+)$')

def indexhanler(request):

    return '<h1></h1>'



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')





@idx.get(r'^/(\w+)$')

@py.router_ables(r'^/(?P<id>\d+)$')

def pythonhandler(request):

    return '<h2></h2>{}'.format(request.groupdict.id)



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except Exception
as e:

        logging.info(e)

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

3、正则表达式化简

类型

含义

对应的正则

str

不包含/的任意字符,默认类型

[^/]+

word

字母和数字

\w+

int

纯数字,正负数

[+-]?\d+

float

正负号,数字,包含

[+-]?\d+.\d+

any

包含/的任意字符。

.+

类型映射到正则表达式;就是使用format函数的填空模式。
TYPEPATTERNS = {

    'str'  : r'[^/]+',

    'word' : r'\w+',

    'int'  : r'[+-]?\d+',

    'float': r'[+-]?\d+.\d+',

    'any' : r'.+'

}



name = 'id'

t = 'int'

print('/(?P<{}>{})'.format(name,TYPEPATTERNS.get(t,TYPEPATTERNS['str'])))

捕获匹配用户的输入,捕获到分组名,然后对应正则表达式。

 
   

src = '/student/{name:str}/{id:int}'

import re

# pattern = r'/{(\w+):(\w+)}'

pattern = r'/{([^{}:]*):([^{}:]*)}'

regix = re.compile(pattern)

matcher = regix.search(src)



def repl(mathcer):

    name = matcher.group(1)

    t = matcher.group(2)

    return '/(?P<{}>{})'.format(name,TYPEPATTERNS.get(t,TYPEPATTERNS['str']))

# print(matcher.group(1))

# print(matcher.group(2))



print(regix.sub(repl,src))

根据用户输入/{id:int}/{name:str}  把这些信息转化为对应的正则表达式。

from webob.dec import wsgify

from webob.exc import
HTTPNotFound

from webob import
Response,Request

import logging

import re

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)

class AttrDict:

    def __init__(self,d:dict):

        self.__dict__.update(d if isinstance(d,dict)else
{})



    def __setattr__(self, key, value):

        raise NotImplementedError



    def __repr__(self):

        return '<AttrDict{}>'.format(self.__dict__)



    def __len__(self):

        return len(self.__dict__)



class RouterAbles:

    pa = r'/{([^{}:]+):?([^{}:]*)}'

    _regex = re.compile(pa)



    TYPEPATTERNS = {

        'str': r'[^/]+',

        'word': r'\w+',

        'int': r'[+-]?\d+',

        'float': r'[+-]?\d+.\d+',

        'any': r'.+'

    }



    def repl(self,matcher):

        name = matcher.group(1)

        t = matcher.group(2)

        return  '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t, self.TYPEPATTERNS['str']))



    def pase(self,src):

        return self._regex.sub(self.repl,src)





    def __init__(self,prefix:str=''):

        self.__prefix
= prefix.rstrip('\\/')

        self.__ROUTERABLES
= []



    def router_register(self,rule,*method):

        def _router_register(handler):

            self.__ROUTERABLES.append(

                (tuple(map(lambda
x:x.upper(),method)),

                 re.compile(self.pase(rule)),handler))

            print(1,self.__ROUTERABLES)

            return handler

        return _router_register



    def get(self,pattern):

        return self.router_register(pattern,'GET')



    def post(self,pattern):

        return self.router_register(pattern,'POST')



    def head(self,pattern):

        return self.router_register(pattern,"HEAD")





    def match(self,request:Request):

        if not request.path.startswith(self.__prefix):

            return None



        for method,pattern,handler
in self.__ROUTERABLES:

            if not method
or request.method.upper() in method:

                matcher =
pattern.match(request.path.replace(self.__prefix,'',1))

                if matcher:

                    # request.groups = matcher.groups()

                    #
print(2,request.groups)

                    request.groupdict =
AttrDict(matcher.groupdict())

                    print(3,request.groupdict)

                    return handler(request)





class App:



    _ROUTER = []



    @classmethod

    def app_regsieter(cls,*routerables:RouterAbles):

        for routerable
in routerables:

            cls._ROUTER.append(routerable)

            print(4,cls._ROUTER)



    @wsgify

    def __call__(self, request):

        for routerable
in self._ROUTER:

            response =
routerable.match(request)

            if response:

                return response

        raise HTTPNotFound()





idx = RouterAbles('/')

py = RouterAbles('/python')



App.app_regsieter(idx,py)



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

@idx.router_register(r'^/{id:int}$')

def handler(request):

    id = ''

    if request.groupdict:

        id =
request.groupdict.id

    return '<h1></h1>{}'.format(request.groupdict.id)



# @py.get(r'^/$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')

@py.router_register(r'^/{id}$')

def pythonhandler(request):

    if request.groupdict:

        id = request.groupdict.id

        return '<h2></h2>{}'.format(id)



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

   
except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

访问方式:

127.0.0.1:9000/python/1234

127.0.0.1:9000/123

上例中缺点是捕获的信息sub函数捕获的全部为str。转化的话。需要改造sub函数。

方法:1、路由注册的时候,将用户指定的rule(@py.router_register(r'^/{id}$'))添加入路由表三元组中。添加的时候调用parse函数。

2、parse函数中的返回值为:模式匹配sub匹配用户rule中的name和类型,sub(两个参数,调用另外一个函数depl,rule)。

3、depl函数中,根据信息。提前指定的表格,按照名字和类型,将类型转化为对应的正则表达式类型。

用户输入三种的形式的匹配,没写的话采用默认值。

拼接字符串的形式:

改造parse函数的代码

from webob.dec import
wsgify

from webob.exc import
HTTPNotFound

from webob import
Response,Request

import logging

import re

from wsgiref import
simple_server





FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class AttrDict:

    def __init__(self,d:dict):

        self.__dict__.update(d if isinstance(d,dict)else
{})



    def __setattr__(self, key, value):

        raise NotImplementedError



    def __repr__(self):

        return '<AttrDict{}>'.format(self.__dict__)



    def __len__(self):

        return len(self.__dict__)



class RouterAbles:

    pa = r'/{([^{}:]+):?([^{}:]*)}'

    _regex = re.compile(pa)



    TYPEPATTERNS = {

        'str': r'[^/]+',

        'word': r'\w+',

        'int': r'[+-]?\d+',

        'float': r'[+-]?\d+.\d+',

        'any': r'.+'

    }



    # def repl(self,matcher):

    #    
print(matcher,']]]')

    #    
name = matcher.group(1)

    #    
t = matcher.group(2)

    #    
s1 = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t,
self.TYPEPATTERNS['str']))

    #    
print('----',s1)

    #    
return  s1

    #

    # def pase(self,rule):

    #    
s2= self._regex.sub(self.repl,rule)

    #    
print('+-+-',rule)

    #    
print('=====',s2)

    #    
return s2



    def parse(self,src: str):

        start = 0

        repl = ''

        types = {}



        TYPECAST = {

            'str': str,

            'word': str,

            'int': int,

            'float': float,

            'any': str

        }

        matchers = self._regex.finditer(src)

        for i, matcher in enumerate(matchers):

            name = matcher.group(1)

            t = matcher.group(2)

            types[name] = TYPECAST.get(t, str)



            repl +=
src[start:matcher.start()]



            tmp = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t, self.TYPEPATTERNS['str']))



            repl += tmp



            start = matcher.end()

        else:

            repl += src[start:]



        return repl, types



    def __init__(self,prefix:str=''):

        self.__prefix
= prefix.rstrip('\\/')

        self.__ROUTERABLES
= []



    def router_register(self,rule,*method):

        def _router_register(handler):

            pattern ,types
= self.parse(rule)

            self.__ROUTERABLES.append(

                (tuple(map(lambda
x:x.upper(),method)),

                 re.compile(pattern),types,handler))

            print(1,self.__ROUTERABLES)

            return handler

        return _router_register



    def get(self,pattern):

        return self.router_register(pattern,'GET')



    def post(self,pattern):

        return self.router_register(pattern,'POST')



    def head(self,pattern):

        return self.router_register(pattern,"HEAD")





    def match(self,request:Request):

        if not request.path.startswith(self.__prefix):

            return None



        for method,pattern,trans,handler in self.__ROUTERABLES:

            if not method
or request.method.upper() in method:

                matchers =
pattern.match(request.path.replace(self.__prefix,'',1))

                if matchers:

                    newdict ={}

                    for k,v in matchers.groupdict().items():

                        newdict[k] = trans[k](v)

                    # request.groups = matcher.groups()

                    #
print(2,request.groups)

                    request.vars =
AttrDict(matchers.groupdict())

                    # print(3,request.groupdict)

                    return handler(request)





class App:



    _ROUTER = []



    @classmethod

    def app_regsieter(cls,*routerables:RouterAbles):

        for routerable
in routerables:

            cls._ROUTER.append(routerable)

            print(4,cls._ROUTER)



    @wsgify

    def __call__(self, request):

        for routerable
in self._ROUTER:

            response =
routerable.match(request)

            if response:

                return response

        raise HTTPNotFound()





idx = RouterAbles('/')

py = RouterAbles('/python')



App.app_regsieter(idx,py)



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

@idx.router_register(r'^/{id:int}$')

def handler(request):

    id = ''

    if request.vars:

        id = request.vars.id

    return '<h1></h1>{}'.format(id)



# @py.get(r'^/$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')

@py.router_register(r'^/{id}$')

def pythonhandler(request):

    if request.vars:

        id = request.vars.id

        return '<h2></h2>{}'.format(id)



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

app中,可以使用字典保存所有的router实例。因为每一个router的实例的前缀不同,完全使用前缀为key,router实例为value组成字典。,以后在call方法中,就不需要遍历列表了。只是需要提取request的path的前缀就可以和字典的key匹配了。提高了效率。

4、框架处理流程

客户端发来http请求,被wsgi服务器处理后传递给app的__call__方法。

App中遍历已经注册的router ,router的match来判断自己能不能处理,前缀匹配,看到注册的规则。(规则是装饰器已经转换成了命名分组的正则表达式了)

如果由某一个注册的正则表达式匹配,就把回去的参数放到request中,调用注册时候的映射handler传入request。

Handler处理以后,返回response。App中拿到response的数据,返回给wsgi。

Handler返回的仅仅是数据,将数据填入HTML中,将新生成的HTML字符串返回给客户端,就是网页技术。模板技术。

五、flask实现

1、模板

HTML:就是格式和数据混在一起的超文本。数据格式的描述。

XML:数据描述。

动态数据很难缓存。缓存是没有用的。

import re

from io import StringIO,BytesIO



d = {'id':5,'name':'tom','age':20}





class Template:

    _pattern = '{{([a-zA-Z0-9_]+)}}'

    regex = re.compile(_pattern)



    @classmethod

    def render(cls,template,data:dict):

        html = StringIO()



        with open(template,encoding='utf-8')as f:

            for line in f :

                start = 0

                newline = ''

                for matcher in cls.regex.finditer(line):

                    newline  += line[start:matcher.start()]

                    print(matcher,matcher.group(1))

                    key = matcher.group(1)

                    tmp = data.get(key,'')

                    newline += str(tmp)

                    start = matcher.end()

else:

                    newline += line[start:]

                html.write(newline)



            print(html.getvalue())

        html.close()



filename = 'index.html'

Template.render(filename,d)

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>wcl</title>

</head>



<body>

显示数据<br>

{{id}}{{name}}{{age}}

</body>

</html>

渲染后的代码:

2 <_sre.SRE_Match object; span=(3, 9),
match='{{id}}'> id

2 <_sre.SRE_Match object; span=(9, 17),
match='{{name}}'> name

2 <_sre.SRE_Match object; span=(17, 24),
match='{{age}}'> age

1 <!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>wcl</title>

</head>

<body>

<h1>显示数据</h1>

<p>5tom20</p>

</body>

</html>

2、jinja

1)简介

基于模块的引擎。设计思想来自Django的模板引擎,与其及其相似。

文档:http://jinja.pocoo.org/docs/2.10/

http://docs.jinkan.org/docs/jinja2/

2)安装

安装:pip install jinjia2

pip install Markupsafe

3)模板构建

当前目录下,新建包webarch,下面闯进一个目录templates,该目录下新建一个HTML模板文件index.html

常用的模式

模板代码:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

显示数据<br>

<ul>

    {% for id,name,age in userlist %}

    <li>{{loop.index}}{{id}}
,{{name}},{{age}}</li>li>

    {% endfor %}

</ul>

total{{usercount}}ren

</body>

</html>

Template文件代码:

from jinja2 import Environment
,PackageLoader,select_autoescape,FileSystemLoader



env = Environment(

    loader=PackageLoader('webarch','templates'),

    autoescape=select_autoescape(['html','xml'])

)

# env1 = Environment(loader=FileSystemLoader('templates'))



# d = {'id':5,

#      'name':'tom',

#      'age':20,

#      'list':[]

# }

# d = {

#     'userlist':[

#         (1,'tom',20),

#         (3,'jeery',23),

#         (7,'ll',28)

#     ]

# }



def render(name,data:dict):



    template = env.get_template('index.html')

    html = template.render(**data)

    return html

3、json

from .web import RouterAbles,Request,Response,App

from .template import
render





idx = RouterAbles('/')

py = RouterAbles('/python')



App.app_regsieter(idx,py)



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

@idx.router_register(r'^/{id:int}$')

def handler(request):

    userlist = [

        (3,'tom',20),

        (5,'jerry',23),

        (6,'ll',25),

        (7,'ls',30)

    ]



    d = {'userlist':userlist,'usercount':len(userlist)}

    # res = Response(json=d)      #json支持

    # return res

    return render('index.html',d)

    # id = ''

    # if request.vars:

    #    
id = request.vars.id

    # return
'<h1></h1>{}'.format(id)



# @py.get(r'^/$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')

@py.router_register(r'^/{id}$')

def pythonhandler(request):

    userlist = [

        (3, 'tom', 20),

        (5, 'jerry', 23),

        (6, 'll', 25),

        (7, 'ls', 30)

    ]



    d = {'userlist':
userlist, 'usercount': len(userlist)}

    return render('index.html', d)

    # res = Response(json=d)      #json支持

    # return res

    # if request.vars:

    #    
id = request.vars.id

    #    
return '<h2></h2>{}'.format(id)

4、模块化

将所有的代码组织成包和模块。

1.app.py

2.webarch(package)

(1)__init__.py

(2)template.py

(3)web.py

(4)templates(package)

Index.html

完整代码:

(1)app.py    (server)

from wsgiref import simple_server

from webarch import
App



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

(2)__init__.py    (handler函数)

from .web import RouterAbles,Request,Response,App

from .template import
render





idx = RouterAbles('/')

py = RouterAbles('/python')



App.app_regsieter(idx,py)



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

@idx.router_register(r'^/{id:int}$')

def handler(request):

    userlist = [

        (3,'tom',20),

        (5,'jerry',23),

        (6,'ll',25),

        (7,'ls',30)

    ]



    d = {'userlist':userlist,'usercount':len(userlist)}

    return render('index.html',d)

    # id = ''

    # if request.vars:

    #    
id = request.vars.id

    # return
'<h1></h1>{}'.format(id)



# @py.get(r'^/$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')

@py.router_register(r'^/{id}$')

def pythonhandler(request):

    userlist = [

        (3, 'tom', 20),

        (5, 'jerry', 23),

        (6, 'll', 25),

        (7, 'ls', 30)

    ]



    d = {'userlist':
userlist, 'usercount': len(userlist)}

    return render('index.html', d)

    # if request.vars:

    #    
id = request.vars.id

    #    
return '<h2></h2>{}'.format(id)

(3)template.py   (渲染模块加载文件)

from jinja2 import
Environment ,PackageLoader,select_autoescape,FileSystemLoader



env = Environment(

    loader=PackageLoader('webarch','templates'),

    autoescape=select_autoescape(['html','xml'])

)

# env1 = Environment(loader=FileSystemLoader('templates'))



# d = {'id':5,

#      'name':'tom',

#      'age':20,

#      'list':[]

# }

# d = {

#     'userlist':[

#         (1,'tom',20),

#         (3,'jeery',23),

#         (7,'ll',28)

#     ]

# }



def render(name,data:dict):

"""



:param name:
去模块目录搜索此模板名的文件

:param data:   字典

:return:  字符串

"""

template = env.get_template('index.html')

    html = template.render(**data)

    return html

(4)web.py  (app,routerable,attrdict类)

from webob.dec import
wsgify

from webob.exc import
HTTPNotFound

from webob import
Response,Request

import logging

import re







FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class AttrDict:

    def __init__(self,d:dict):

        self.__dict__.update(d if isinstance(d,dict)else
{})



    def __setattr__(self, key, value):

        raise NotImplementedError



    def __repr__(self):

        return '<AttrDict{}>'.format(self.__dict__)



    def __len__(self):

        return len(self.__dict__)



class RouterAbles:

    pa = r'/{([^{}:]+):?([^{}:]*)}'

    _regex = re.compile(pa)



    TYPEPATTERNS = {

        'str': r'[^/]+',

        'word': r'\w+',

        'int': r'[+-]?\d+',

        'float': r'[+-]?\d+.\d+',

        'any': r'.+'

    }



    # def repl(self,matcher):

    #    
print(matcher,']]]')

    #    
name = matcher.group(1)

    #    
t = matcher.group(2)

    #    
s1 = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t,
self.TYPEPATTERNS['str']))

    #    
print('----',s1)

    #    
return  s1

    #

    # def pase(self,rule):

    #    
s2= self._regex.sub(self.repl,rule)

    #    
print('+-+-',rule)

    #    
print('=====',s2)

    #    
return s2



    def parse(self,src: str):

        start = 0

        repl = ''

        types = {}



        TYPECAST = {

            'str': str,

            'word': str,

            'int': int,

            'float': float,

            'any': str

        }

        matchers = self._regex.finditer(src)

        for i, matcher in enumerate(matchers):

            name = matcher.group(1)

            t = matcher.group(2)

            types[name] = TYPECAST.get(t, str)



            repl +=
src[start:matcher.start()]



            tmp = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t, self.TYPEPATTERNS['str']))



            repl += tmp



            start = matcher.end()

        else:

            repl += src[start:]



        return repl, types



    def __init__(self,prefix:str=''):

        self.__prefix
= prefix.rstrip('\\/')

        self.__ROUTERABLES
= []



    def router_register(self,rule,*method):

        def _router_register(handler):

            pattern ,types = self.parse(rule)

            self.__ROUTERABLES.append(

                (tuple(map(lambda
x:x.upper(),method)),

                 re.compile(pattern),types,handler))

            #print(1,self.__ROUTERABLES)

            return handler

        return _router_register



    def get(self,pattern):

        return self.router_register(pattern,'GET')



    def post(self,pattern):

        return self.router_register(pattern,'POST')



    def head(self,pattern):

        return self.router_register(pattern,"HEAD")





    def match(self,request:Request):

        if not request.path.startswith(self.__prefix):

            return None



        for method,pattern,trans,handler in self.__ROUTERABLES:

            if not method
or request.method.upper() in method:

                matchers =
pattern.match(request.path.replace(self.__prefix,'',1))

                #print('+++',trans)

                if matchers:

                    newdict ={}

                    for k,v in matchers.groupdict().items():

                        newdict[k] =
trans[k](v)

                        #print('+-+-',trans[k](v))

                      
#print(1,matchers.groupdict().items())

                        #print(k,v)

                        #print('---',newdict)

                    # request.groups =
matcher.groups()

                    #
print(2,request.groups)

                    request.vars = AttrDict(newdict)

                    # print(3,request.groupdict)

                    return handler(request)





class App:



    _ROUTER = []



    @classmethod

    def app_regsieter(cls,*routerables:RouterAbles):

        for routerable
in routerables:

            cls._ROUTER.append(routerable)

            print(4,cls._ROUTER)



    @wsgify

    def __call__(self, request):

        for routerable
in self._ROUTER:

            response =
routerable.match(request)

            if response:

                return response

        raise HTTPNotFound()

(5)index.html文件内容,渲染模板

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

显示数据<br>

<ul>

    {% for id,name,age in userlist %}

    <li>{{loop.index}}{{id}}
,{{name}},{{age}}</li>li>

    {% endfor %}

</ul>

total{{usercount}}ren

</body>

</html>

5、拦截器interceptor

拦截器是在请求处理的环节的某一处加入处理,有可能是中断后续的处理

分类:链式、洋葱式的。

拦截点不同:

1)请求时候拦截的

2)响应时候拦截

影响面:

1)全局拦截,在app中拦截

2)局部拦截,在router中拦截

拦截器可以是多个,多个拦截器是有顺序的,数据的response前执行的命名为preinterceptor,之后命名为postinterceptor。

加入拦截器功能的方式

(1)app和router类直接加入。

把拦截器相关方法,属性分别添加到相关的类中。

实现简单

(2)Mixin

App和router类都需要这个拦截器功能,这个两个类没有什么关系,可以使用Mixin方式,将属性、方法组合进来。App拦截器适合使用第二种,但是router的拦截器是每个实例不一样的,所以使用第一种方式实现。

拦截器函数的设计,fn不能影响数据向下一级的传递,也就是透明的。

Ip拦截的简单代码;

from webob.exc import Request







def ip(request:Request):

    if request.remote_addr.startswish('192'):

        return request

   

    else:

        return None

6、发布的模式

from distutils.core import setup

import glob





setup(name='webarch',     #
名字

      version='0.0.1',     #版本

      description='python wsgi web framework',   #描述信息

      author='wcl',                            #作者

      author_email='604603701@qq.com',     
#作者邮箱

      url='www.',                         
#包的主页

      packages=['webarch'],      #打包列表,

      data_files=glob.glob('webarch/templates/*')  #返回列表     配置文件,图片等文件列表

      )



#打包

##python setup.py sdist



# 安装

#pip install webarch

7、总结

(1)熟悉wsgi的编程接口

(2)强化模块、类封装的思想

(3)增强业务分析的能力。

框架基本具备了wsgi web框架
的基本实现。

权限验证,SQL注入的检测功能都需要使用拦截器功能实现

完整代码:

(1)__init__.py文件

from .web import RouterAbles,Request,Response,App

from .template import
render





idx = RouterAbles('/')

py = RouterAbles('/python')



App.app_regsieter(idx,py)



def ip(request:Request):

    if request.remote_addr.startswish('192'):

        return request



    else:

        return None



py.register_preinterceprot(ip)



# @idx.get(r'^/$')

# @idx.router_register(r'^/(?P<id>\d+)$')

@idx.router_register(r'^/{id:int}$')

def handler(request):

    userlist = [

        (3,'tom',20),

        (5,'jerry',23),

        (6,'ll',25),

       
(7,'ls',30)

    ]



    d = {'userlist':userlist,'usercount':len(userlist)}

    # res = Response(json=d)      #json支持

    # return res

    return render('index.html',d)

    # id = ''

    # if request.vars:

    #    
id = request.vars.id

    # return '<h1></h1>{}'.format(id)



# @py.get(r'^/$')

# @py.get('^/(\w+)$')

# @py.router_register(r'^/(?P<id>\d+)$')

@py.router_register(r'^/{id}$')

def pythonhandler(request):

    userlist = [

        (3, 'tom', 20),

        (5, 'jerry', 23),

        (6, 'll', 25),

        (7, 'ls', 30)

    ]



    d = {'userlist':
userlist, 'usercount': len(userlist)}

    return render('index.html', d)

    # res = Response(json=d)      #json支持

    # return res

    # if request.vars:

    #    
id = request.vars.id

    #    
return '<h2></h2>{}'.format(id)

(2)类文件web.py

from webob.dec import
wsgify

from webob.exc import
HTTPNotFound

from webob import
Response,Request

import logging

import re







FORMAT = '%(asctime)s
%(threadName)s %(thread)d %(message)s'

logging.basicConfig(format=FORMAT,level=logging.INFO)





class AttrDict:

    def __init__(self,d:dict):

        self.__dict__.update(d if isinstance(d,dict)else
{})



    def __setattr__(self, key, value):

        raise NotImplementedError



    def __repr__(self):

        return '<AttrDict{}>'.format(self.__dict__)



    def __len__(self):

        return len(self.__dict__)



class RouterAbles:

    pa = r'/{([^{}:]+):?([^{}:]*)}'

    _regex = re.compile(pa)



    TYPEPATTERNS = {

        'str': r'[^/]+',

        'word': r'\w+',

        'int': r'[+-]?\d+',

        'float': r'[+-]?\d+.\d+',

        'any': r'.+'

    }



    # def repl(self,matcher):

    #    
print(matcher,']]]')

    #    
name = matcher.group(1)

    #    
t = matcher.group(2)

    #    
s1 = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t,
self.TYPEPATTERNS['str']))

    #    
print('----',s1)

    #    
return  s1

    #

    # def pase(self,rule):

    #  
  s2=
self._regex.sub(self.repl,rule)

    #    
print('+-+-',rule)

    #    
print('=====',s2)

    #    
return s2



    def parse(self,src: str):

        start = 0

        repl = ''

        types = {}



        TYPECAST = {

            'str': str,

            'word': str,

            'int': int,

            'float': float,

            'any': str

        }

        matchers = self._regex.finditer(src)

        for i, matcher in enumerate(matchers):

            name = matcher.group(1)

            t = matcher.group(2)

            types[name] = TYPECAST.get(t, str)



            repl +=
src[start:matcher.start()]



            tmp = '/(?P<{}>{})'.format(name, self.TYPEPATTERNS.get(t, self.TYPEPATTERNS['str']))



            repl += tmp



            start = matcher.end()

        else:

            repl += src[start:]



        return repl, types



    def __init__(self,prefix:str=''):

        self.__prefix
= prefix.rstrip('\\/')

        self.__ROUTERABLES
= []



        #拦截器

        self.pre_interceptor
= []

        self.post_interceptor
= []



    def register_preinterceprot(self,fn):

        self.pre_interceptor.append(fn)

        return fn



    def register_postinterport(self,fn):

        self.post_interceptor.append(fn)

        return fn





    def router_register(self,rule,*method):

        def _router_register(handler):

            pattern ,types = self.parse(rule)

            self.__ROUTERABLES.append(

                (tuple(map(lambda
x:x.upper(),method)),

                 re.compile(pattern),types,handler))

            #print(1,self.__ROUTERABLES)

            return handler

        return _router_register



    def get(self,pattern):

        return self.router_register(pattern,'GET')



    def post(self,pattern):

        return self.router_register(pattern,'POST')



    def head(self,pattern):

        return self.router_register(pattern,"HEAD")





    def match(self,request:Request):

        if not request.path.startswith(self.__prefix):

            return None



        #请求拦截,处理request

        for fn in self.pre_interceptor:

            request = fn(request)

            if not request:

                return None



        for method,pattern,trans,handler in self.__ROUTERABLES:

            if not method
or request.method.upper() in method:

                matchers =
pattern.match(request.path.replace(self.__prefix,'',1))

                #print('+++',trans)

                if matchers:

                    newdict ={}

                    for k,v in matchers.groupdict().items():

                        newdict[k] =
trans[k](v)

                        #print('+-+-',trans[k](v))

                      
#print(1,matchers.groupdict().items())

                        #print(k,v)

                       
#print('---',newdict)

                    # request.groups = matcher.groups()

                    #
print(2,request.groups)

                    request.vars = AttrDict(newdict)

                    # print(3,request.groupdict)

                    return handler(request)





class App:



    _ROUTER = []

    #全局拦截

    PRE_INTERCEPTOR = []

    POST_INTERCEPTOR = []



    #全局拦截器注册函数

    @classmethod

    def register_preinterceptor(cls,fn):

        cls.PRE_INTERCEPTOR.append(fn)

        return fn



    @classmethod

    def register_postinterceptor(cls,fn):

        cls.POST_INTERCEPTOR.append(fn)



    @classmethod

    def app_regsieter(cls,*routerables:RouterAbles):

        for routerable
in routerables:

            cls._ROUTER.append(routerable)

            print(4,cls._ROUTER)



    @wsgify

    def __call__(self, request):

        #全局请求拦截

        for fn in self.PRE_INTERCEPTOR:

            request = fn(request)



        #全局拦截响应

        for routerable
in self._ROUTER:

            response =
routerable.match(request)

            for fn in self.POST_INTERCEPTOR:

                response = fn(request,response)



            if response:

                return response

        raise HTTPNotFound()

(3)template.py文件

from jinja2 import
Environment ,PackageLoader,select_autoescape,FileSystemLoader



env = Environment(

    loader=PackageLoader('webarch','templates'),

    autoescape=select_autoescape(['html','xml'])

)

# env1 =
Environment(loader=FileSystemLoader('templates'))



# d = {'id':5,

#      'name':'tom',

#      'age':20,

#      'list':[]

# }

# d = {

#     'userlist':[

#         (1,'tom',20),

#         (3,'jeery',23),

#         (7,'ll',28)

#     ]

# }



def render(name,data:dict):

    """



    :param name:
去模块目录搜索此模板名的文件

    :param data:   字典

    :return:  字符串

    """

   
template = env.get_template('index.html')

    html = template.render(**data)

    return html

(4)app.py 文件

from wsgiref import
simple_server

from webarch import
App



if __name__ == '__main__':

    server = simple_server.make_server('127.0.0.1',9000,App())

    try:

        server.serve_forever()

    except KeyboardInterrupt:

        server.shutdown()

        server.server_close()

(5)index.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

显示数据<br>

<ul>

    {% for id,name,age in userlist %}

    <li>{{loop.index}}{{id}}
,{{name}},{{age}}</li>li>

    {% endfor %}

</ul>

total{{usercount}}ren

</body>

</html>

Python的web开发的更多相关文章

  1. 如何用Python做Web开发?——Django环境配置

    用Python做Web开发,Django框架是个非常好的起点.如何从零开始,配置好Django开发环境呢?本文带你一步步无痛上手.     概念 最近有个词儿很流行,叫做“全栈”(full stack ...

  2. 在 Windows 上使用 Python 进行 web 开发

    本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 上一篇我们介绍了在Windows 10下进行初学者入门开发Python的指 ...

  3. 【python】 web开发入门

    进入Web开发 现在你完成了Python忍者训练,准备深入Ptyhon的Web开发,但现在的问题是有很多的框架,从中选择最好的框架非常困难,但从初学者的角度出发,Flask基本Web框架将非常适合We ...

  4. [python] python django web 开发 —— 15分钟送到会用(只能送你到这了)

    1.安装python环境 1.1 安装python包管理器: wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py   1. ...

  5. Python做web开发,推荐几个能立马上手的小项目

    Python这门优美的语言是非常适合web开发的,基于Python的Django框架简单便捷且很强大. 那么作为新手该如何上手这门语言?一切不敲代码的学编程手段都是扯淡,今天就推荐一些适合新手练手的P ...

  6. (第一篇)记一次python分布式web开发(利用docker)

    作者:落阳 日期:2020-12-23 在一次项目开发中,决定使用docker+nginx+flask+mysql的技术栈来开发,用此系列文章记录开发的过程. 系列文章,当前为第一篇,记录一次pyth ...

  7. 【python】web开发

    No1: hello.py def application(environ,start_response): start_response('200 OK',[('Content-Type','tex ...

  8. python的web开发环境Django配置

    我的系统的windows10: 第一步,安装python3.5 第二步,配置django,如图所示,在python的安装目录下的Scripts里面执行:pip install Django,我这儿提示 ...

  9. 从Python到Web开发

    基础部分: 1-编程基础及Python环境部署 2-Python基础语法-内存管理-运算符-程序控制 3-Python内置结构-列表 4-Python数据类型之元组-字符串 5-python的封装与结 ...

随机推荐

  1. element ui 渲染超过上百条数据时页面卡顿,更流畅的加载大量数据

    问题:element ui table渲染上百条数据,页面渲染开始出现延时 解决方案:使用pl-table 注意:设置use-virtual并给定table高度

  2. 问题记录 java.lang.NoClassDefFoundError: org/dom4j/DocumentException

    客户端调webservice服务产生以下错误 AxisFault faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.genera ...

  3. Linked List & List Node All In One

    Linked List & List Node All In One 链表 & 节点 链表类型 单链表 双链表 环形链表 / 循环链表 Singly Linked List (Uni- ...

  4. Android Studio & zh-Hans

    Android Studio & zh-Hans https://developer.android.com/studio?hl=zh-cn https://developer.android ...

  5. empty Checker

    empty Checker "use strict"; /** * * @author xgqfrms * @license MIT * @copyright xgqfrms * ...

  6. Apache HTTP Server & WS (websockets)

    Apache HTTP Server & WS (websockets) Apache HTTP Server Version 2.4 https://httpd.apache.org/doc ...

  7. taro 如何展示多行文本 省略号

    taro 如何展示多行文本 省略号 webkit-box-orient: vertical; See the Pen Pure CSS multiline text with ellipsis by ...

  8. nasm astricmp函数 x86

    xxx.asm: %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export as ...

  9. 比特币大涨之际,VAST空投火爆来袭!

    昨天特斯拉宣布投资了15亿美元的比特币,消息一出,币圈沸腾,比特币瞬间拉升,突破4万美元关口,现价46000美元!大涨20%,又刷新历史新高! 另外NGK项目热度最高的BGV也是不断刷新历史新高,数据 ...

  10. 离场定高转弯DF与CF的对比

    也许是刚学会CAD的缘故,配合风螺旋插件,画图的感觉真是蛮爽的,忍不住画了一张又一张. 接着昨天的离场保护区,我们来聊一下PBN指定高度转弯保护区的画法.指定高度转弯的计算本身没有太多复杂的地方,真正 ...