小程序开发:上传图片到腾讯云

这是小程序开发第二篇,主要介绍如何上传图片到腾讯云,之所以选择腾讯云,是因为腾讯云免费空间大😂 准备工作 上传图片主要是将图片上传到腾讯云对象存储(COS)。 要使用对象存储 API,需要先执行以下步骤: 购买腾讯云对象存储(COS)服务 在腾讯云 对象存储控制台 里创建一个 Bucket 在控制台 个人 API 密钥 页面里获取 AppID、SecretID、SecretKey 内容 编写一个请求签名算法程序(或使用任何一种服务端 SDK) 计算签名,调用 API 执行操作 所以我们要做的准备工作有: 进入腾讯云官网,注册帐号 登录云对象存储服务(COS)控制台,开通COS服务,创建资源需要上传的Bucket 在小程序官网上配置域名信息(否则无法在小程序中发起对该域名的请求) 这些配置过程这里就不做说明了,接下来主要介绍步骤4、5。 小程序上传图片到 cos 流程如下图: 在这个过程中我们需要实现的是,鉴权服务器返回签名的步骤以及小程序的相关步骤。 COS鉴权服务 使用对象存储服务 COS 时,可通过 RESTful API 对 COS 发起 HTTP 匿名请求或 HTTP 签名请求,对于签名请求,COS 服务器端将会进行对请求发起者的身份验证。 匿名请求:HTTP 请求不携带任何身份标识和鉴权信息,通过 RESTful API 进行 HTTP 请求操作。 签名请求:HTTP 请求时添加签名,COS服务器端收到消息后,进行身份验证,验证成功则可接受并执行请求,否则将会返回错误信息并丢弃此请求。 腾讯云COS对象存储,基于密钥 HMAC (Hash Message Authentication Code) 的自定义 HTTP 方案进行身份验证。 上传图片是一个签名请求,需要进行签名验证。之所以我们 签名流程 客户通过对 HTTP 请求进行签名,并将签名后的请求发送至腾讯云进行签名验证,具体流程如下图所示。 我们使用 sdk 开发,这个流程大致了解下就行,签名的实现 sdk 已经包含,只需要调用方法即可。 ...

2017-08-27 · 3 min · 461 words

Python 装饰器使用指南

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装饰器基础知识 首先看一下这段代码 def deco(fn): print "I am %s!" % fn.__name__ @deco def func(): pass # output I am func! # 没有执行func 函数 但是 deco 被执行了 HUGOMORE42 在用某个@decorator来修饰某个函数func时 @decorator def func(): pass 其解释器会解释成下面这样的语句: func = decorator(func) 其实就是把一个函数当参数传到另一个函数中,然后再回调,但是值得注意的是装饰器必须返回一个函数给func 装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二大特性是,装饰器在加载模块时立即执行。 装饰器何时执行 装饰器的一个关键特性是,它们在被装饰的函数定义后立即运行。这通常在导入是(python 加载模块时)。 看下下面的示例: registry = [] # registry 保存被@register 装饰的函数的引用 def register(func): # register 的参数是一个函数 print('running register(%s)' % func) # 打印被装饰的函数 registry.append(func) # 把 func 存入 `registery` return func # 返回 func:必须返回函数,这里返回的函数与通过参数传入的一样 @register # `f1` 和 `f2`被 `@register` 装饰 def f1(): print('running f1()') @register def f2(): print('running f2()') def f3(): # <7> print('running f3()') def main(): # main 打印 `registry`,然后调用 f1()、f2()和 f3() print('running main()') print('registry ->', registry) f1() f2() f3() if __name__=='__main__': main() # <9> 运行代码结果如下: ...

2017-08-15 · 8 min · 1578 words

自定义 Sanic Exception

Sanic 是一个和类Flask 的基于Python3.5+的web框架,它使用了 Python3 异步特性,有远超 flask 的性能。 编写 RESTful API 的时候,我们会定义特定的异常错误类型,比如我定义的错误返回值格式为: { "error_code": 0, "message": "string", "text": "string" } 不同的错误信息指定不同的 http 状态码。 sanic 提供了几种常用的 exception: NotFound(404) Forbidden(403) ServerError(500) InvalidUsage(400) Unauthorized(401) RequestTimeout(408) PayloadTooLarge(413) 这些 exception 继承自 SanicException 类: class SanicException(Exception): def __init__(self, message, status_code=None): super().__init__(message) if status_code is not None: self.status_code = status_code 从上述代码可以看出,这些异常只能指定 message 和 status_code 参数,那我们可不可以自定义 exception 然后在自定义的 exception 中增加参数呢?下面的代码是按照这个思路修改后的代码: class ApiException(SanicException): def __init__(self, code, message=None, text=None, status_code=None): super().__init__(message) self.error_code = code self.message = message self.text = text if status_code is not None: self.status_code = status_code 使用后我得到一个结果如下: ...

2017-08-05 · 2 min · 395 words

小程序开发:python sanic 实现小程序登录注册

开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步。这篇文章将介绍 python + sanic + 微信小程序实现用户快速注册登录全栈方案。 微信小程序登录时序图如下: 这个流程分为两大部分: 小程序使用 wx.login() API 获取 code,调用 wx.getUserInfo() API 获取 encryptedData 和 iv,然后将这三个信息发送给第三方服务器。 第三方服务器获取到 code、encryptedData和 iv 后,使用 code 换取 session_key,然后将 session_key 利用 encryptedData 和 iv 解密在服务端获取用户信息。根据用户信息返回 jwt 数据,完成登录。 下面我们先看一下小程序提供的 API。 小程序登录 API 在这个授权登录的过程中,用到的 API 如下: wx.login wx.getUserInfo wx.chekSession 是可选的,这里并没有用到。 wx.login(OBJECT) 调用此接口可以获取登录凭证(code),以用来换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key)。 如果接口调用成功,返回结果如下: 参数名 类型 说明 errMsg String 调用结果 code String 用户允许登录后,回调内容会带上 code(有效期五分钟),开发者需要将 code 发送到开发者服务器后台,使用code 换取 session_key api,将 code 换成 openid 和 session_key code 换取 session_key 开发者服务器使用登录凭证 code 获取 session_key 和 openid。其中 session_key 是对用户数据进行加密签名的密钥。为了自身应用安全,session_key 不应该在网络上传输。所以这一步应该在服务器端实现。 ...

2017-07-30 · 5 min · 929 words

CSS入门指南-3:定位元素

这是《CSS设计指南》的读书笔记,用于加深学习效果。 前一篇CSS入门指南-2:盒子模型、浮动和清除介绍了css盒子模型、浮动和清除,这一篇介绍 css元素的定位。 定位(position) CSS 布局的核心是 position 属性,对元素盒子应用这个属性,可以相对于它在常规文档流中的位置重新定位。 position 属性有4个值:static、relative、absoulte、fixed,默认值为 static。 接下来我会用以下四个段落来逐个说明这些属性是什么意思。 <p id="first">First Paragraph</p> <p id="Second">Second Paragraph</p> <p id="specialpara">Third Paragraph</p> <p id="fourth">First Paragraph</p> 静态定位(static) 我们先看一下四个段落都采用静态定位的效果。 静态定位下,每个元素在处在常规文档流中,它们都是块级元素,所以会在页面中自上而下地堆叠。 相对定位(relative) 现在我把第三段的 position 属性设置为 relative。 p#specialpara { position: relative; top: 25px; left: 30px; } 因为相对定位相对的是它原来在文档流中的位置(默认位置),所以如果只设置 position 样式不会有任何变化。这里我同时设置了 top 和 left 属性来改变它的位置。 现在它的效果如图所示: 现在,第三段从原来的元素(body)中挣脱了出来,与它在文档中的默认位置相比向下移动了25像素,向右移动了30像素。 需要注意的是,除了这个元素自己相对于原始位置挪动了一下以外,页面没有任何改变。这个元素原来占据的空间没有动,其他元素也没动。 这时,如果不想第四段被它挡住,可以给第四段设置一个 margin-top 值。 绝对定位(absoulte) 绝对定位跟静态定位和相对定位相比,它会把元素彻底从文档流中拿出来。 我们把 position 改为绝对定位看一下: p#specialpara { position: absoulte; top: 25px; left: 30px; } 效果如图: 可以看到,第三段原来的位置被回收了。这说明绝对定位的元素脱离了常规文档流,它现在是相对于顶级元素 body 在定位。 现在就涉及到一个概念:定位上下文,这个后边说,先继续看最后一种定位方式:固定定位。 盒子位移属性是如何工作? 盒子的位移属性有四个“top、right、bottom和left”,用来指定元素的定位位置和方向。这些属性只能在元素的“position”属性设置了“relative、absolute和fixed”属性值,才生效。 对于相对定位元素,这些属性的设置让元素从默认位置移动。例如,top设置一个值“20px”在一个相对定位的元素上,这个元素会在原来位置向下移动“20px”。 ...

2017-07-26 · 2 min · 290 words

理解JWT(JSON Web Token)认证及实践

最近想做个小程序,需要用到授权认证流程。以前项目都是用的 OAuth2 认证,但是Sanic 使用OAuth2 不太方便,就想试一下 JWT 的认证方式。 这一篇主要内容是 JWT 的认证原理,以及python 使用 jwt 认识的实践。 几种常用的认证机制 HUGOMORE42 HTTP Basic Auth HTTP Basic Auth 在HTTP中,基本认证是一种用来允许Web浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式,通常用户名和明码会通过HTTP头传递。 在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用Base64算法编码。例如,提供的用户名是Aladdin、口令是open sesame,则拼接后的结果就是Aladdin:open sesame,然后再将其用Base64编码,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最终将Base64编码的字符串发送出去,由接收者解码得到一个由冒号分隔的用户名和口令的字符串。 优点 基本认证的一个优点是基本上所有流行的网页浏览器都支持基本认证。 缺点 由于用户名和密码都是Base64编码的,而Base64编码是可逆的,所以用户名和密码可以认为是明文。所以只有在客户端和服务器主机之间的连接是安全可信的前提下才可以使用。 接下来我们看一个更加安全也适用范围更大的认证方式 OAuth。 OAuth OAuth 是一个关于授权(authorization)的开放网络标准。允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。现在的版本是2.0版。 严格来说,OAuth2不是一个标准协议,而是一个安全的授权框架。它详细描述了系统中不同角色、用户、服务前端应用(比如API),以及客户端(比如网站或移动App)之间怎么实现相互认证。 名词定义 Third-party application: 第三方应用程序,又称"客户端"(client) HTTP service:HTTP服务提供商 Resource Owner:资源所有者,通常称"用户"(user)。 User Agent:用户代理,比如浏览器。 Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。 Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。 OAuth 2.0 运行流程如图: (A)用户打开客户端以后,客户端要求用户给予授权。 (B)用户同意给予客户端授权。 (C)客户端使用上一步获得的授权,向认证服务器申请令牌。 (D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。 (E)客户端使用令牌,向资源服务器申请获取资源。 (F)资源服务器确认令牌无误,同意向客户端开放资源。 优点 快速开发 实施代码量小 维护工作减少 如果设计的API要被不同的App使用,并且每个App使用的方式也不一样,使用OAuth2是个不错的选择。 缺点: OAuth2是一个安全框架,描述了在各种不同场景下,多个应用之间的授权问题。有海量的资料需要学习,要完全理解需要花费大量时间。 OAuth2不是一个严格的标准协议,因此在实施过程中更容易出错。 了解了以上两种方式后,现在终于到了本篇的重点,JWT 认证。 ...

2017-07-23 · 2 min · 398 words

CSS入门指南-2:盒子模型、浮动和清除

这是CSS设计指南的读书笔记,用于加深学习效果。 上一篇介绍了css 的工作原理,这一篇主要介绍盒子模型和浮动。 盒子模型 所谓盒子模型,就是浏览器为页面中的每个HTML元素生成的矩形盒子。这些盒子们都要按照可见版式模型在页面上排布。 HUGOMORE42 可见的页面版式主要由三个属性控制:position、display和float。 position:控制页面上元素的位置关系 display:控制元素是堆叠、并排还是不在页面出现 float:提供控制的方式,以便吧元素组成多栏布局 元素盒子的属性可以分成三组: 边框(board)。可以甚至边框的宽窄、样式和颜色 内边距(padding)。可以甚至盒子内容区与边框的间距 外边距(margin)。可以设置盒子与相邻元素的间距 元素盒子还有一个背景层,可以改变颜色,也可以添加图片。 简写样式 CSS为边框、内边距和外边距分别规定了简写属性,每个简写声明中,属性值得顺序都是上、右、下、左。 比如: { margin-top: 5px; margin-right: 10px; margin-bottom: 12px; margin-left: 8px; } 使用简写则为这样: { margin: 12px 10px 12px 8px; } 如果有一个值没写,那么则使用对边的值。 比如: {margin: 12px 10px 12px;} /*等同于*/ { margin: 12px 10px 12px 10px; } 如果只写一个值,则4个边都取这个值。 {margin: 12px;} /*等同于*/ {margin: 12px 12px 12px 12px;} 另外每个盒子的属性也分三个粒度,这三个粒度从一般到特殊分别举例如下: { border: 2px dashed red; } 混合使用三种粒度的简写属性达成设计目标是很常见的。比如,想为盒子的上边和下边添加4像素的红色边框,为左边添加1像素宽的红色边框,而右边没有。可以这么写: {border: 4px solid red;} /* 先给4条边设置相同的样式*/ {border-left-width: 1px;} /* 修改左边框宽度*/ {border-fight: none;} /*移出右边框*/ 盒子边框 border 有三个相关属性。 宽度(border-width)。可以使用thin、medium和thick等文本值,也可以使用除百分比和负值之外的任何绝对值。 样式(border-style)。有none、hidden、dotted、dashed等文本值。 颜色(border-color)。可以使用任意颜色值,包括RGB、HSL、十六进制颜色值和颜色关键字。 盒子内边距 内边距是盒子内容区与盒子边框之间的距离。 上图的样式为: p { font: 16px helvetica, sans-serif; width: 220px; border: 2px solid red; background-color: #caebff; } 可以看到在没有设定内边距的情况下,内容紧挨着边框。 设定边框后: ...

2017-07-19 · 3 min · 571 words

微信公号DIY:MongoDB 简易ORM & 公号记账数据库设计

前两篇 微信公号DIY 系列: 微信公号DIY:一小时搭建微信聊天机器人 微信公号DIY:训练聊天机器人&公号变身图片上传工具 介绍了如何使用搭建&训练聊天机器人以及让公号支持图片上传到七牛,把公号变成一个七牛图片上传客户端。这一篇将继续开发公号,让公号变成一个更加实用的工具账本(理财从记账开始)。 代码: 项目代码已上传至github,地址为gusibi/momo:https://github.com/gusibi/momo HUGOMORE42 账本功能 账本是一个功能比较简单应用,公号内只需要支持: 记账(记账,修改金额,取消记账) 账单统计(提供数据和图片形式的统计功能) 当然后台管理功能就比较多了,这个以后再介绍。 对于数据存储,我选择的是MongoDB(选MongoDB的原因是,之前没用过,想试一下),我们先看下MongoDB和关系型数据库的不同。 MongoDB 什么是MongoDB ? MongoDB 是由C++语言编写的,是一个开放源代码的面向文档的数据库,易于开发和缩放。 mongo和传统关系数据库的最本质的区别在那里呢?MongoDB 是文档模型。 关系模型和文档模型的区别在哪里? 关系模型需要你把一个数据对象,拆分成零部件,然后存到各个相应的表里,需要的是最后把它拼起来。举例子来说,假设我们要做一个CRM应用,那么要管理客户的基本信息,包括客户名字、地址、电话等。由于每个客户可能有多个电话,那么按照第三范式,我们会把电话号码用单独的一个表来存储,并在显示客户信息的时候通过关联把需要的信息取回来。 而MongoDB的文档模式,与这个模式大不相同。由于我们的存储单位是一个文档,可以支持数组和嵌套文档,所以很多时候你直接用一个这样的文档就可以涵盖这个客户相关的所有个人信息。关系型数据库的关联功能不一定就是它的优势,而是它能够工作的必要条件。 而在MongoDB里面,利用富文档的性质,很多时候,关联是个伪需求,可以通过合理建模来避免做关联。 MongoDB 概念解析 在mongodb中基本的概念是文档、集合、数据库,下表是MongoDB和关系型数据库概念对比: SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数据库 table collection 数据库表/集合 row document 数据记录行/文档 column field 数据字段/域 index index 索引 table joins 表连接,MongoDB不支持 primary key primary key 主键,MongoDB自动将_id字段设置为主键 通过下图实例,我们也可以更直观的的了解Mongo中的一些概念: 接下来,我从使用的角度来介绍下如何使用 python 如何使用MongoDB,在这个过程中,我会实现一个简单的MongoDB的ORM,同时也会解释一下涉及到的概念。 简易 Python MongoDB ORM python 使用 mongodb 首先,需要确认已经安装了 PyMongo,如果没有安装,使用以下命令安装: pip install pymongo # 或者 easy_install pymongo 详细安装步骤参考: PyMongo Installing / Upgrading ...

2017-07-16 · 4 min · 659 words

使用swagger 生成 Flask RESTful API

什么是 RESTful 什么是REST REST(英文:Representational State Transfer,又称具象状态传输)是Roy Thomas Fielding博士于2000年在他的博士论文[1] 中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。 REST 的核心是可编辑的资源及其集合,用符合 Atom 文档标准的 Feed 和 Entry 表示。每个资源或者集合有一个惟一的 URI。系统以资源为中心,构建并提供一系列的 Web 服务。 在 REST 中,开发人员显式地使用 HTTP 方法,对系统资源进行创建、读取、更新和删除的操作: 使用 POST 方法在服务器上创建资源 使用 GET 方法从服务器检索某个资源或者资源集合 使用 PUT 方法对服务器的现有资源进行更新 使用 DELETE 方法删除服务器的某个资源 如果一个架构符合REST原则,就可以称它为RESTful架构。 RESTful API 设计定义 以下是几个RESTful API的几个概念。 资源(Resource):系统上的所有事物都被抽象为资源(一篇文章,一张照片,一段语音) 集合(Collection):一组资源的合辑称为集合(几篇文章,几张照片) 路径(Endpoint):路径又称”终点“,表示API的具体网址(每个网址代表一种资源) 那么一个设计良好的RESTful API应该遵循哪些原则呢? 协议 API与用户的通信协议总是使用HTTPs协议。 域名 应该尽量将API部署在专用域名,例如: https://apis.gusibi.com API地址和版本 在url中指定API版本。比如: https://apis.gusibi.com/v1 以资源为中心设计URL 资源是RESTful API的核心元素,所有的操作都是针对特定资源进化的。而资源就是URL表示的,所以简洁、清晰、结构化的URL设计是至关重要的。 在RESTful 架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。我们来看一下 Github 的例子: /users/:username/repos /users/:org/repos /repos/:owner/:repo /repos/:owner/:repo/tags /repos/:owner/:repo/branches/:branch 使用正确的Method 对于资源的具体操作类型,使用HTTP method 表示。 以下是常用的HTTP方法。 ...

2017-07-11 · 4 min · 778 words

微信公号DIY:训练聊天机器人&公号变身图片上传工具

上一篇 一小时搭建微信聊天机器人 介绍了如何搭建一个可用的聊天机器人,但是和机器人聊完你会发现,聊天机器人实在是太傻了,来回就那么几句。这是因为我们给聊天机器人的数据太少,他只能在我们给的训练集中找它认为最合适的。那么,如何导入更多的训练数据呢? 我能想到最简单的方法是找对话的数据,然后把这些数据作为训练数据训练机器人。 感谢 candlewill 已经收集好了大量的训练数据,dialog_corpus https://github.com/candlewill/Dialog_Corpus 。 HUGOMORE42 这个库中包含电影台词、中英文短信息、自然语言处理相关的数据集、小黄鸡语料等。这里我选择电影台词语料。 语料地址为:dgk_lost_conv:https://github.com/rustch3n/dgk_lost_conv chatterbot 训练逻辑处理模块 这个模块提供训练机器人的方法,chatterbot自带了通过输入list来训练([“你好”, “你好啊”] 后者是前者的回答)以及通过导入Corpus格式文件来训练的方式。 这里我们选择使用第一种,通过输入list来训练机器人。 处理训练数据 首先下载数据集: wget https://codeload.github.com/rustch3n/dgk_lost_conv/zip/master # 解压 $ unzip dgk_lost_conv-master.zip 我们先打开一个文件看下数据结构: E M 你得想想办法 我弟弟是无辜的 M 他可是美国公民啊 M 对此我也无能为力 M 你当然能 M 再去犯罪现场看看 定能证实清白 M 你看 我不过是个夜间办事员而已 M 你若真想解决问题 M 最好等领事来 M 他早上才上班 M 我很抱歉 E M 那我自己来搞定 M 你兄弟 M 关在哪个监狱? M 索纳监狱 E M 怎么了? M 那里关的都是最穷凶极恶的罪犯 M 别的监狱都不收 .conv 语料文件中:E 是分隔符 M 表示会话。因为我是使用输入list 的方式训练数据,这时我可以以分隔符E为分隔,将一段对话放入一个list中,那么上述例子中的训练数据应该被格式化为: ...

2017-07-08 · 3 min · 571 words