Service

Service类常用于封装与上下文有关的逻辑。

如果Model的第一个参数类型是ContextRequest, Response或者Service,那么这就不再是一个Model类型,而是Service类型。框架对Service类的参数进行实例化时,会递归地实例化它的各个Context, Request, Response, Service类型的成员。

示例

下面这段代码可以实现10秒内只允许一个用户最多访问3次。

from lessweb import Application, Context, HttpStatus, interceptor
from redis import Redis, ConnectionPool


redis_conn = ConnectionPool(host='127.0.0.1', port=6379, db=0)


def global_processor(ctx: Context):
    ctx.box['redis'] = Redis(connection_pool=redis_conn)
    return ctx()


class RedisServ:
    ctx: Context

    @property
    def redis(self) -> Redis:
        session = self.ctx.box.get('redis')
        if session is None:
            raise ValueError('redis session not available')
        return session


class LimitServ:
    redis_serv: RedisServ
    ctx: Context

    @property
    def key(self):
        return f'count/{self.ctx.request.ip}'

    def touch(self) -> int:
        count = self.redis_serv.redis.get(self.key)
        if count is None:
            count = b'0'
            self.redis_serv.redis.set(self.key, value=count, ex=10)

        self.redis_serv.redis.incr(self.key)
        return int(count.decode())


def limit_checker(ctx: Context, limitServ: LimitServ):
    count = limitServ.touch()
    print(count)
    if count >= 3:
        ctx.response.set_status(HttpStatus.Forbidden)
        return 'Forbidden'
    else:
        return ctx()


@interceptor(limit_checker)
def hello():
    return 'hello'


app = Application()
app.add_interceptor('.*', '*', global_processor)
app.add_get_mapping('/hello', hello)

if __name__ == '__main__':
    app.run()

请求1:curl -L "http://localhost:8080/hello"
返回:hello

请求2:curl -L "http://localhost:8080/hello"
返回:hello

请求3:curl -L "http://localhost:8080/hello"
返回:hello

请求4:curl -L "http://localhost:8080/hello" (10秒内访问)
返回:Forbidden