1.前言
在使用过程中,我尽量将程序编写成异步的,首先进行安装:
python -m pip install sanic
sanic的文档写得很详细,但是在使用过程中我还是有些问题。
下面记录的都是我在使用sanic过程中遇到的问题,后续有新问题会继续补充:
- 1.blueprint
- 2.html templates编写(引入jinja2)
- 3.session(引入sanic_session)
- 4.缓存(引入aiocache)
- 5.api接口验证(自定义一个装饰器)
- 6.恶意将其他域名绑定到你的网站独立ip
2.问题记录
2.1.blueprint
借用官方文档的例子,一个简单的sanic服务就搭好了:
# main.py
from sanic import Sanic
from sanic.response import json
app = Sanic()
@app.route("/")
async def test(request):
return json({"hello": "world"})
#访问http://0.0.0.0:8000/即可
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
上面的例子可以当做一个完整的小应用,关于blueprint的概念,可以这么理解,一个蓝图可以独立完成某一个任务,包括模板文件,静态文件,路由都是独立的,而一个应用可以通过注册许多蓝图来进行构建。
比如我现在编写的项目,我使用的是功能式架构,具体如下:
├── server.py
├── static
│ └── novels
│ ├── css
│ │ ├── chapter.css
│ │ ├── content.css
│ │ ├── index.css
│ │ ├── main.css
│ │ └── result.css
│ ├── img
│ │ ├── bookMark.png
│ │ ├── favicon.ico
│ │ ├── read_bg.png
│ │ └── read_content.png
│ └── js
│ ├── list.js
│ └── main.js
├── template
│ └── novels
│ ├── chapter.html
│ ├── content.html
│ ├── donate.html
│ ├── feedback.html
│ ├── index.html
│ ├── main.html
│ └── result.html
└── views
└── novels_blueprint.py
可以看到,总的templates以及静态文件还是放在一起,但是不同的blueprint则放在对应的文件夹中,还有一种分区式架构,则是将不同的templats以及static等文件夹全都放在不同的的blueprint中。
最后只要将每个单独的blueprint在主启动文件进行注册就好,比如我的这个项目:
# server.py
#!/usr/bin/env python
from sanic import Sanic
from novels_search.views.novels_blueprint import bp
app = Sanic(__name__)
app.blueprint(bp)
app.run(host="0.0.0.0", port=8000, debug=True)
具体的novels_blueprint.py
请点击这里
2.2.html templates编写
编写web服务,自然会涉及到html,sanic自带有html函数,但这并不能满足有些需求,故引入jinja2迫在眉睫,使用方法也很简单:
# novels_blueprint.py片段
from sanic import Blueprint
from jinja2 import Environment, PackageLoader, select_autoescape
# 初始化blueprint并定义静态文件夹路径
bp = Blueprint('novels_blueprint')
bp.static('/static', './static/novels')
# jinjia2 config
env = Environment(
loader=PackageLoader('views.novels_blueprint', '../templates/novels'),
autoescape=select_autoescape(['html', 'xml', 'tpl']))
def template(tpl, **kwargs):
template = env.get_template(tpl)
return html(template.render(kwargs))
@bp.route("/")
async def index(request):
return template('index.html', title='index')
这样,就实现了jinja2 的引入。
2.3.session
sanic对此有一个第三方插件sanic_session
,用法非常简单,见官方例子如下:
import asyncio_redis
from sanic import Sanic
from sanic.response import text
from sanic_session import RedisSessionInterface
app = Sanic()
# Token from https://github.com/subyraman/sanic_session
class Redis:
"""
A simple wrapper class that allows you to share a connection
pool across your application.
"""
_pool = None
async def get_redis_pool(self):
if not self._pool:
self._pool = await asyncio_redis.Pool.create(
host='localhost', port=6379, poolsize=10
)
return self._pool
redis = Redis()
# pass the getter method for the connection pool into the session
session_interface = RedisSessionInterface(redis.get_redis_pool, expiry=604800)
@app.middleware('request')
async def add_session_to_request(request):
# before each request initialize a session
# using the client's request
await session_interface.open(request)
@app.middleware('response')
async def save_session(request, response):
# after each request save the session,
# pass the response to set client cookies
await session_interface.save(request, response)
@app.route("/")
async def test(request):
# interact with the session like a normal dict
if not request['session'].get('foo'):
request['session']['foo'] = 0
request['session']['foo'] += 1
response = text(request['session']['foo'])
return response
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8888, debug=True)
2.4.缓存
我在项目中主要使用redis作为缓存,使用aiocache很方便就完成了我需要的功能,当然自己利用aioredis编写也不会复杂到哪里去。
@cached(ttl=1800, cache=RedisCache, key_from_attr='url', serializer=PickleSerializer(),
endpoint=REDIS_DICT.get('REDIS_ENDPOINT', None), port=REDIS_DICT.get('REDIS_PORT', None), namespace="main")
async def cache_owllook_novels_chapter(url, netloc):
async with aiohttp.ClientSession() as client:
html = await target_fetch(client=client, url=url)
if html:
soup = BeautifulSoup(html, 'html5lib')
selector = RULES[netloc].chapter_selector
if selector.get('id', None):
content = soup.find_all(id=selector['id'])
elif selector.get('class', None):
content = soup.find_all(class_=selector['class'])
else:
content = soup.find_all(selector.get('tag'))
return str(content) if content else None
return None
带上装饰器,什么都解决了。
2.5.api接口验证
在编写接口的时候,有些接口可能需要在headers中加个验证头或者token,sanic官方貌似并没有提供,解决起来很简单,可以在request时候进行验证,代码如下:
# 比如想验证一个请求的 Owllook-Api-Key值是否跟自己约定的值一样,这里写个装饰器就好
from functools import wraps
from sanic.response import json
from novels_search.config import AUTH
def authenticator(key):
"""
:param keys: 验证方式 Owllook-Api-Key : Maginc Key, Authorization : Token
:return: 返回值
"""
def wrapper(func):
@wraps(func)
async def authenticate(request, *args, **kwargs):
value = request.headers.get(key, None)
if value and AUTH[key] == value:
response = await func(request, *args, **kwargs)
return response
else:
return json({'msg': 'not_authorized', 'status': 403})
return authenticate
return wrapper
至于使用
@api_bp.route("/bd_novels/<name>")
@authenticator('Owllook-Api-Key')
async def bd_novels(request, name):
pass
具体见例子
2.6.恶意将其他域名绑定到你的网站独立ip
前两天突然发现别人没经过我的同意就将自己的域名绑定到我的网站,不能忍,解决办法有不少,web服务器写配置解决,或者代码层面解决,我说下第二种。
首先,定义你允许访问的HOST,再获取访问时获取的host,比如:
# config.py
HOST = ['127.0.0.1:8001']
# sanic获取host
host = request.headers.get('host', None)
那么就可以在sanic中间件中定义:
# 当host不满足条件就调到baidu
@app.middleware('request')
async def add_session_to_request(request):
host = request.headers.get('host', None)
if not host or host not in HOST:
return redirect('http://www.baidu.com')
相关推荐
- 后端生成自定义token,可以包含OpenID、过期时间、随机字符串等信息,然后使用session_key对token进行加密。 - 将加密后的token返回给前端,前端存储在本地。 - 当需要向后台请求数据时,前端在请求头中添加此...
- 为了增强安全性,通常我们会基于openid和session_key生成一个自定义的token。这可以使用JWT(JSON Web Token)或者自定义的签名算法实现。 - JWT包含三部分:Header、Payload和Signature。Header和Payload都是...
### Cookie、Session与Token的区别及使用详解 #### 一、Cookie **定义**: Cookie是一种用于在客户端保持状态的方案。简单来说,当你访问一个网站时,该网站可能会在你的计算机上留下一些信息(如用户名、密码等),...
2. **生成token**:在Action类中,可以使用`TokenActionSupport`作为基类,或者自定义Action类并实现`TokenAware`接口。这两个方法都会自动在用户请求时生成token并存入session。 3. **表单集成**:在JSP页面的表单...
asp.net WebAPI Token Oauth2.0授权自定义返回结果(包括登录正确返回,登录失败返回)。 详细参考:https://blog.csdn.net/u013546115/article/details/105580532
### tokenSession拦截器详解 #### 一、引言 在Web开发中,为了防止用户重复提交表单数据,通常会采用各种技术手段进行控制。在Java Web应用开发中,Struts2框架提供了一种非常实用的方法来解决这个问题——通过...
在IT行业中,Token认证签名加密是一种常见的安全机制,主要用于确保数据传输的安全性和验证请求的合法性。这个主题涉及了几个核心概念,包括Token、加密和签名,这些都是构建安全网络服务的关键要素。 1. **Token**...
最近在搞springboot的模块化开发,集成了shiro+jwt实现restful接口的token认证。 需新增测试表: CREATE TABLE `t_user` ( `user_id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT, `user_name` varchar(32...
生成的Token可以存储在服务器的Session或数据库中,以便后续验证。 2. **返回Token给客户端**:服务器将生成的Token作为响应的一部分发送给客户端。客户端需要妥善保存这个Token,通常存储在本地存储(如浏览器的...
spring1.2 + struts1.2 + hibernate3.2 标准的配置,初学者可以参考,可以直接开发,省去写框架的麻烦 ,同时里面还有防刷新等自定义类,也是比较好的源, 还有字符截取等 此为第一部分,需要将三个包合在一起解压
请注意共三部分要全下才能解压,此为第三部分,需要将三个包合在一起解压 spring1.2 struts1.2 hibernate 框架 token防刷新防重复提交(自定义) md5加密 验证码 绝对超值,呵呵
c#在WebAPI中使用Token认证的方式登录,增强保密。
用libcurl和libjson实现人人网从APP key 获取access_token和session_key,用于CPP SDK,http://wiki.dev.renren.com/wiki/Cpp-sdk-1.0,填入main.cpp中的session key here即可调用。
在Web开发中,Session和Token是两种常见的身份验证机制,用于保护用户数据安全。下面将详细解释这两个概念,以及如何创建带有时间戳的Session值和设置Token。 **一、Session** Session是服务器端存储用户状态的一...
在Web开发中,Session、Cookie和Token是三种常见的身份验证机制,它们各有特点,并在不同的场景下发挥着关键作用。理解它们的关系以及Cookie的局限性对于构建安全的Web应用程序至关重要。 首先,让我们来探讨...
Redis是一个高性能的键值数据库,常用于存储临时数据,如session、token等。由于Redis支持内存存储,读写速度非常快,适合处理频繁的token验证操作。将token存储在Redis中,可以快速检查token的有效性,同时,Redis...
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,...
通过ajax分配相应的clientID和Secret及用户名和...测试页面click_me_please_iframe.html包含相应的刷新和认证,同时refresh_token以文件的形式进行存储,方便下次程序直接使用,不必要在产生新的token;开发工具是vs2017
认证成功后,服务器端生成一个令牌(token),例如JWT(JSON Web Token),返回给客户端。客户端在后续的WebSocket连接请求中将此token附加在HTTP头部中,服务器端接收token并验证合法性。 ```java // 在WebSocket...
这里,我们可以看到自定义的认证获取方式可以介入,通过配置好的方法来处理认证请求,这通常涉及到从数据库或其他存储中查询用户信息,并创建一个`OAuth2Authentication`对象。 一旦`OAuth2Authentication`对象创建...