在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:HeraldStudio/herald-webservice开源软件地址:https://github.com/HeraldStudio/herald-webservice开源编程语言:JavaScript 97.2%开源软件介绍:herald-webservice小猴偷米 2018 WebService3 后端,使用 Node.js + Koa 构建。 使用说明部署说明生产环境下请使用 生产环境部署前,建议对 redis 进行配置,以满足 WebService3 自动缓存的需求:
接口使用说明接口互解释文档点击 https://myseu.cn/ws3/api/ 可获得简明的接口文档。 返回格式按照 ReSTful 接口设计的原则,只要请求经由 WebService3 处理,无论请求成功与否,都将遵循下面的返回格式:
用户登录用户登录时,需要向后端发送登录请求: curl -X POST http://myseu.cn/ws3/auth -d cardnum=一卡通号 -d password=统一身份认证密码 -d platform=平台标识符 其中,平台标识符 为一个字符串,推荐格式为小写字母和短横线的组合,例如 后端收到登录请求,经过验证后,将返回一个16进制字符串( curl -X GET http://myseu.cn/ws3/api/card -H token:xxxxxxxx
当然,对于路由处理程序中不需要用户登录的功能,仍可以允许不带 过期机制为了减轻数据库膨胀,超过一定时间未调用接口的用户将会自动过期。该过期时间(天数)在 点击量统计
用户点击轮播图或活动时,前端需要(与普通接口一样带 token)调用对应的上报接口(轮播图为 请只在用户主动点击时调用点击量上报接口,以保证点击量统计的准确性。 开发文档介绍WebService3 是小猴偷米最新的后端架构,基于 Node.js + Koa 进行开发,为模块开发者提供了一系列非常方便的接口,可用于小猴偷米各类查询、服务、管理系统后端的渐进式开发。 WebService3 基于自研的 kf-router,可以根据 js 文件结构自动组织路由,无需独立配置。我们将从 Hello World 开始,介绍 WebService3 的模块开发方式。 开始开发需要安装 Yarn 代替 npm 作为包管理器。 git clone https://github.com/heraldstudio/herald-webservice
cd herald-webservice
cp sdk/sdk.example.json sdk/sdk.json
yarn dev Windows 用户须先阅读 node-gyp 的安装指南 ,确保安装设置 Python 2.7 以避免编译错误。 Hello World//: /api/hello.js 或 /api/hello/index.js
exports.route = {
async get() { // 同步方法可省略 async
return 'Hello, World!'
}
} 执行 请求参数kf-router 提供了 注意,本服务端使用较严格的参数解析, //: /api/hello.js 或 /api/hello/index.js
exports.route = {
async get() {
let { a, b } = this.params // 相当于 let a = this.params.a, b = this.params.b
return parseInt(a) + parseInt(b)
},
async post({ c, d }) {
return parseInt(c) + parseInt(d)
}
// put, delete 也适用
} 执行 认证 APIWebService3 提供了完整的统一身份认证机制,如果模块需要,可以获取用户的一卡通号码、统一身份认证密码、身份识别码、统一身份认证 Cookie 等信息。 要求登录那么,如何在书写路由处理程序时表明当前功能是否需要登录呢?一般的设定是,只要程序读取了 下面的例子展示了一个需要登录的功能,并且介绍了 exports.route = {
async get() {
// 一卡通号、明文密码、姓名、学号
// 为了保证隐私安全,我们将对上线的模块严加审查,严禁对明文密码进行存储、显示、发送给第三方
let { cardnum, password, name, schoolnum } = this.user
// 加密解密函数,需要存储的敏感信息要加密,从数据库中取出要解密
let { encrypt, decrypt } = this.user
console.log(decrypt(encrypt(cardnum)) === cardnum) // true
// 两个用于区分用户的 API,有一定差别:
// 这里的 token 是不具有隐私性的伪 token,不能用于解密数据,只用于区分用户
// 同一个实体用户在多处登录时,多个端的伪 token 互不相同,真正用于加解密的 token 也互不相同,因此伪 token 多用于与加解密相关的场合。
// 而 identity 是区分实体用户的标志,每个实体用户 identity 一定唯一,多用于用户行为分析等。
let { token, identity } = this.user
return `Hello, ${cardnum}!`
}
} 对游客和用户进行区分当然,如果你需要同时对游客和已登录用户开放同一个功能,并且仍然需要对已登录用户读取用户信息,可以使用下面的范式。在这个范式中,我们对 exports.route = {
async get() {
if (this.user.isLogin) {
return `Hello, ${this.user.cardnum}!`
} else {
return 'Hello, guest!'
}
}
} 上述模块将对已登录用户和游客显示不同的信息。若不对 获取学期通过 上述「学期」均为对象,包含 注意,只要 网络请求WebService3 框架为 exports.route = {
async get() {
let res = await this.get('https://httpbin.org/get') // 请求上游 API
return res.data // axios 将自动对结果执行 JSON.parse;koa 也支持直接返回非字符串类型,将自动执行 JSON.stringify。
}
} 考虑到学校网站的历史原因和爬虫自身的需求,我们对这套 axios API 的默认配置进行了一系列变更:
熔断器(2019/1/23 添加)如果某个上游一直不可用,请求会拥塞在 WebService 上,导致网络变得极其缓慢。因此引入了熔断器(circuit,完整的叫法为 Circuit Breaker)中间件,当某个路由在一分钟的时间窗内连续三次出现如下情况之一:
则会对该路由执行强制性的拒绝服务措施(称作「熔断」),并直接抛出 503,不再执行下游中间件。当最先发生的一次失败移出了这个 1 分钟的时间窗,导致这个时间窗内不再有足够三次实际出错时,熔断器将对该路由允许一次服务(称作「探测」),如果依然失败,则保持熔断状态;如果发现成功,则熔断解除。 自动 Cookie在上文提到的网络请求 API 中,为了爬虫处理方便,我们利用 对于路由处理程序来说,在初始条件下,该 CookieJar 是空的。 与此同时,前述认证 API 提供了
一个典型的例子就是一卡通模块: async get() {
// 显式声明需要用户登录,并带上统一身份认证 Cookie
// 默认是老信息门户 Cookie,如果需要新信息门户 Cookie,可以加参数 { ids6: true }(非常耗时)。
await this.useAuthCookie()
// 带着统一身份认证 Cookie 获取一卡通中心 Cookie
await this.get('http://allinonecard.seu.edu.cn/ecard/dongnanportalHome.action')
// 带着统一身份认证 Cookie 和一卡通中心 Cookie 抓取一卡通页面
let res = await this.get('http://allinonecard.seu.edu.cn/accountcardUser.action')
// Do something with res.data here...
} 通用返回格式 & 错误处理在书写路由处理程序时,对于成功返回和失败返回,推荐使用的返回方式分别如下:
缓存 API通过 async get() {
// 第一次被调用后,数据将缓存 1 小时 10 分钟
// 在接下来这段时间内,重复调用将会直接返回缓存的结果,不再重复执行闭包
return await this.userCache('1h10m', async () => {
await someTimeConsumingTask()
return 'Finished'
})
} 注意:在 HTTP 规范中,只有 缓存的 key缓存的内容默认将按照 async get() {
// 通过附加 key 'world' 进行存储,避免本路由中的两个缓存部分相互混淆
return await this.userCache('world', '1mo', () => { // 缓存 1 个月
return 'Hello, World!'
})
// 附加 key 可以指定多个
return await this.userCache('ws3', 'another-key', 'yet-another-key', '1d', () => { // 缓存 1 天
return 'Hello, WebService3!'
})
} 缓存的公有和私有使用 async get() {
return await this.publicCache('1h', () => {
return 'Cached for everyone!'
})
} 缓存懒抓取模式通过在时间策略串末尾加上加号 async get() {
// 无缓存 => 执行闭包 -> 返回执行结果 -> (若执行成功) 存入缓存
// 有缓存 && 未过期 => 返回缓存
//* 有缓存 && 已过期 => 返回缓存 -> 执行闭包 -> (若执行成功) 更新缓存
return await this.userCache('10s+', () => {
return 'Caches live longer!'
})
} 为了方便理解,懒抓取策略与非懒抓取的区别仅在于缓存存在但过期的情况。在这种情况下,非懒抓取策略将优先回源,回源失败再取缓存,强调数据的时效性;懒抓取策略将优先取缓存,然后在后台更新缓存,强调响应速度。 设置了懒抓取模式的闭包中,上下文 无论是否采用懒抓取,一旦启用缓存,其时间至少为 5 秒,因此时间串 数据库WebService3 本身不强制要求模块自身使用任何数据库,对于用户自身的基本信息,最好提议我们写在 auth 数据库 中。如果模块确实需要使用数据库,可以根据自己的习惯选择合适的 Sqlite3 ORM 进行开发。 目前 WebService3 集成了 sqlongo,可以通过如下方式创建其实例: const db = require('sqlongo')('my_database') 接口互解释接口互解释是指,一部分路由处理程序不仅实现自身的功能,还充当向导的角色,介绍相关的其他接口。有了接口互解释的机制,开发者无需提供接口文档供调用者查阅,只需要通过不断调用接口,即可了解所有接口的使用方法。接口互解释在 GitHub API 中有广泛的应用。 related 中间件提供了接口之间相互解释的 API,以便在不需要接口文档的情况下直接寻找到需要的接口。只要在需要充当向导的接口中尽早调用 //- /api/index.js
this.related('card', {
get: '{ date?: yyyy-M-d, page? } 一卡通信息及消费流水,不带 date 为当日流水',
put: '{ password, amount: float, eacc?=1 } 一卡通在线充值'
}) 如果只有 GET 方法,也可以直接在第二个参数中写介绍。 this.related('srtp', 'SRTP 学分及项目查询') 为了更加清晰明确,适合 WebService3 的特殊情形,我们所使用的接口互解释与 GitHub 的返回格式不同: GET /api => {
success: true,
code: 200,
result: '',
related: [
{
url: '/api/card',
get: '{ date?: yyyy-M-d, page? } 一卡通信息及消费流水,不带 date 为当日流水',
put: '{ password, amount: float, eacc?=1 } 一卡通在线充值'
},
{
url: '/api/srtp',
get: 'SRTP 学分及项目查询'
}
]
} 代码风格
命名规范下面列举了本系统可能用到的一些有多种译法的名词。不同译法可能各有好处,但一个系统内部需要有一致性,因此对于每个名词,随机规定其中一种译法作为标准。 此规范适用于系统的 JSON 返回格式。在代码内部不必严格遵照这个规范。 目前已规定的译法有:
关于分布式爬虫目前状态
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论