Node.js 实现抢票小工具 & 短信通知提醒功能

要知道在深圳上班是非常痛苦的事情,特别是我上班的科兴科技园这一块,去的人非常多,每天上班跟春运一样,如果我能换到以前的大冲上班那就幸福了,可惜,换不得。

尤其是我这个站等车的多的一笔,上班公交挤的不行,车满的时候只有少部分人能硬挤上去。通常我只会用两个字来形容这种人:“公交怪”

想当年我朋友瘦的像只猴还能上去,老子身高182体重72kg挤个公交,不成问题,反手一个阻挡,闷声发大财,前面的阿姨你快点阿姨,别磨磨唧唧的,快上去啊阿姨,嗯?你还想挤掉我?你能挤掉我?你能挤掉我!我当场!把车吃了!

....

咳咳,挤公交是不可能挤公交滴,因为今天我发现了一个可以定制路线的网约巴士公众号【深圳xxx】

但是呢,票经常会被抢光,同时我还我发现,有时候会有人退票,这时候就有空余票了,关键是我不可能时时都在公众号上盯着,于是,我就写了一个抢票+短信通知的小工具

获取接口信息

1.查看页面结构

这个就是订票页面,显示当前月的车票情况,根据图示,红色为已满,绿色为已购,灰色为不可选

如果是可选就是白色的小方块,并且在下面显示余票,如下图所示:

我们打算这么做,

  1. 定时抓取返回的接口信息
  2. 根据接口返回值判断是否有余票

好,审查下源代码看下接口信息,等等,微信浏览器没办法审查源代码,于是

2.使用chrome调试微信公众号网页页面

首先面临个问题,如果直接copy公众号网页Url在chrome打开的话,就会显示这个画面,他被302重定向到了这个页面,所以是行不通的,只有获取OAuth2.0授权才能进去

所以我们得先通过抓包工具,知道手机访问微信公众号网页的时候,需要带什么信息过去,这时候我们就得借助抓包工具,因为我电脑是Mac,用不了 Fiddler ,我用的是 Charles 花瓶,就是下面这位仁兄

借助这个工具,我们只需3步就可以轻松搞定手机数据抓包:

  • 获取本机IP地址和端口
  • 设置代理手机上网
  • 依次执行上面两步

2-1 获取本机IP地址和端口

第一步,找到端口号,一般默认是8088,但是为了确认可以打开 Proxy / Proxy Setting 看下,哦原来我之前设置成了8888

然后找到 Charleshelp / Local IP Address,点击它就会看到自己的本机地址,找到本机地址记下来,然后进行下一步

2-2设置代理手机上网

首先保证手机跟电脑连接的是同一个wifi,然后在wifi设置那里会有设置代理信息,比如我的猴米...不对,小米9手机!设置如下:

输入上一步获取主机名,端口号就ok了

输入完成,点击确定后。 Charles 就会弹出一个对话框,问你是否同意接入代理,点击确定allow就行了。

2-3 用手机访问目标网页

我们用手机访问微信公众号【深圳x出行】进入到抢票页面后,发现 Charles 已经成功抓包到了网页信息,当我们进入这个抢票页面的时候,他会发起两个请求,一个是获取document文档内容,一个post请求获取票务信息。

仔细分析了下,大概明白了业务逻辑:

整个项目技术站是java+jsp,传统写法,用户身份验证主要是cookie+session方案,前端这一块主要是使用 jQuery

当用户进入页面的时候,会携带查询参数,如起始站点,时间,车次等信息和cookie请求document文档, 也就是圈起来的这一块,

而我们想要的核心内容:日历表,一开始是不显示的

因为还要在请求一次

第二次请求,携带cookie和以上的查询参数发起一个post请求,获取当月的车票信息,也就是日历表内容

下面这个是请求当月票务信息,然而发现他返回的是一堆html节点

好吧...估计是获取到之后直接 appenddiv 里面的,然后渲染生成日历表内容

接着在手机上操作,选择两个日期,然后点击下单,发送购票请求,拉取购票接口,我们看下购票接口的请求和返回内容:

看下request 内容,根据字段的意思大概明白是线路,时间,以及车票金额,还有支付方式

在看看返回的内容:返回一个json字符串数据,里面大概涵盖了下单的成功返回码,时间,id号等等信息

2-4 记录所需要的信息内容

根据上面的分析,总结下内容: 整个项目用户身份验证是使用 cookiesession 方案,请求数据用的是 form data 方式,请求字段啥的我们也都清楚,唯独有一点,就是请求余票的时候,返回的是html节点代码,而不是我们预期的json数据,这样就有个麻烦,我们没办法一目了然的明白他余票的时候是如何显示的

所以我们只能通过 chrome 进行调试,才能得出他是如何判断余票的。

我们找个记事本,记录下信息,记录的内容有:

  • 请求余票接口和购票接口的 url 地址
  • cookie 信息 各自的 request 参数字段 user-Agent 信息
  • 各自的 response 返回内容

2-5 设置chrome

有以上信息后,我们就可以开始用chrome调试了, 首先打开 More tools / Network conditions

user-Agent 填入到 Custom里面

2-6 Charles抓包本地请求

因为我们要把获取到的cookie填入到chrome里面,以我们的用户身份去访问网页,所以我们需要在请求目标地址的时候,改包修改cookie

首先我们需要开启 macOS Proxy ,抓包我们的http请求

打开chrome访问目标网址,我们可以看到 Charles

上已经抓包到了我们访问的目标url地址,然后给目标url地址打上断点,方便调试

然后再次访问,这时候断点就生效了,弹出一个tab名为 break points ,可以看到之所以我们还是不能访问到目标网址,是因为 sessionId 不对,所以我们把抓取到的 cookie 在填入到里面,点击 execute

这时候,能够正确跳到目标页面了。

大概看了下他整体布局,和 jQuery 代码 CSS

代码,特别是日历表那一块

审查了下元素发现:

小方块的结构为:

<td class="b">
<span>这里为日期</span>
<span>如果有余票则显示余票数量</span>
</td>
  • td的样式名为 a 代表不可选
  • 样式名为 e 代表已满
  • 样式名为 d 代表已购
  • 样式名为 b 则是我们要找的,代表可选,也就是有余票

到这一步,整个购票流程就清楚了

到时候我们通过Node.js请求的时候,处理返回数据,用正则去判断是否有余票的class名 b ,有余票的话,在获取div里面的余票数量内容就Ok了

2.Node.js 请求目标接口

2-1 分析需要开发的功能点

写代码之前我们需要想好功能点,我们需要什么功能:

  • 请求余票接口
  • 定时请求任务
  • 有余票则自动请求购票接口下订单
  • 调用腾讯云短信api接口发送短信通知
  • 多个用户抢票功能
  • 抢某个日期的票

首先 mkdir ticket 创建名为ticket的文件夹,接着 cd ticket 进入文件夹 npm init 一路瞎几把回车也无妨。 下面开始安装依赖,根据上面的功能需求,我们大概需要:

1.请求工具,这里看个人习惯,你也可以使用原生的 http.request ,我这里选择用的是 axios ,毕竟 axios 在node端底层也是调用 http.request

cnpm install axios --save

2.定时任务 node-schedule

cnpm install node-schedule --save

3.node端选择dom节点工具 cheerio

cnpm install cheerio --save

4.腾讯发短信的依赖包 qcloudsms_js

cnpm install qcloudsms_js

5.热更新包,诺豆的妈妈, nodemom (其实不用也可以)

cnpm install nodemom --save-dev

2-2开发请求余票接口

接着 touch index.js 创建核心js文件,开始编码:

首先引入所有依赖

const axios = require('axios')
const querystring = require("querystring"); //序列化对象,用qs也行,都一样
var QcloudSms = require("qcloudsms_js");
var cheerio = require('cheerio');
var schedule = require('node-schedule');

然后我们先定义请求参数,来一个obj

var obj = {
 data: {
  lineId: 111130, //路线id
  vehTime: 0722, //发车时间,
  startTime: 0751, //预计上车时间
  onStationId: 564492, //预定的站点id
  offStationId: 17990,//到站id
  onStationName: '宝安交通运输局③', //预定的站点名称
  offStationName: "深港产学研基地",//预定到站名称
  tradePrice: 0,//总金额
  saleDates: '17',//车票日期
  beginDate: '',//订票时间,滞空,用于抓取到余票后填入数据
 },
 phoneNumber: 123123123, //用户手机号,接收短信的手机号
 cookie: 'JSESSIONID=TESTCOOKIE', // 抓取到的cookie
 day: "17" //定17号的票,这个主要是用于抢指定日期的票,滞空则为抢当月所有余票
}

接着声明一个名为 queryTicket 的类,为啥要用类呢,因为基于第五个需求点,多个用户抢票的时候,我们分别 new 一下就行了,

同时我们希望能够记录请求余票的次数,和当抢到票后自动停止查询余票得操作,所以给他加上个计数变量 times 和是否停止的变量,布尔值 stop

编写代码:

class QueryTicket{
 /**
  *Creates an instance of QueryTicket.
  * @param {Object} { data, phoneNumber, cookie, day }
  * @param data {Object} 请求余票接口的requery参数
  * @param phoneNumber {Number} 用户手机号,短信需要用到
  * @param cookie {String} cookie信息
  * @params day {String} 某日的票,如'18'
  * @memberof QueryTicket 请求余票接口
  */
 constructor({ data, phoneNumber, cookie, day }) {
  this.data = data
  this.cookie = cookie
  this.day = day
  this.phoneNumber = phoneNumber
  this.postData = querystring.stringify(data)
  this.times = 0;  //记录次数
  var stop = false //通过特定接口才能修改stop值,防止外部随意串改
  this.getStop = function () { //获取是否停止
   return stop
  }
  this.setStop = function (ifStop) { //设置是否停止
   stop = ifStop
  }
 }
}

下面开始定义原型方法,为了方便维护,我们把逻辑拆分成各个函数

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代码...
 }
  init(){}//初始化
  handleQueryTicket(){}//查询余票的逻辑
  requestTicket(){} //调用查询余票接口
  handleBuyTicket(){} //购票相关逻辑
  requestOrder(){}//调用购票接口
  handleInfoUser(){}//通知用户的逻辑
  sendMSg(){} //发短信接口
}

所有数据都是基于查询余票的操作,因此我们先开发这部分功能

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代码...
 }
 //初始化,因为涉及到异步请求,所以我们使用`async await`
  async init(){
     let ticketList = await this.handleQueryTicket() //返回查询到的余票数组
  }
  //查询余票的逻辑
  handleQueryTicket(){
  let ticketList = [] //余票数组
  let res = await this.requestTicket()
  this.times++ //计数器,记录请求查询多少次
  var str = res.data.replace(/\\/g, "") //格式化返回值
  var $ = cheerio.load(`<div class="main">${str}</div>`) // cheerio载入查询接口response的html节点数据
  let list = $(".main").find(".b") //查找是否有余票的dom节点
  // 如果没有余票,打印出请求多少次,然后返回,不执行下面的代码
  if (!list.length) {
   console.log(`用户${this.phoneNumber}:无票,已进行${this.times}次`)
   return
  }

  // 如果有余票
  list.each((idx, item) => {
   var str = $(item).html() //str这时格式是<span>21</span><span>&$x4F59;0</span>
   //最后一个span 的内容其实"余0",也就是无票,只不过是被转码了而已
   //因此要在下一步对其进行格式化
   var arr = str.split(/<span>|<\/span>|\&\#x4F59\;/).filter(item => !!item === true)
   let data = {
    day: arr[0],
    ticketLeft: arr[1]
   }

   //如果是要抢指定日期的票
   if (this.day) {
   //如果有指定日期的余票
    if (parseInt(data.day) === parseInt(data.day)) {
     ticketList.push(data)
    }
   } else {
   //如果不是,则返回查询到的所有余票
    ticketList.push(data)
   }
  })
  return ticketList
  }
   //调用查询余票接口
  requestTicket(){
  return axios.post('http://weixin.xxxx.net/ebus/front/wxQueryController.do?BcTicketCalendar', this.postData, {
   headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12A365 MicroMessenger/5.4.1 NetType/WIFI",
    "Cookie": this.cookie
   }
  })
  }
  handleBuyTicket(){} //购票相关逻辑
  requestOrder(){}//调用购票接口
  handleInfoUser(){}//通知用户的逻辑
  sendMSg(){} //发短信接口
}

来解释下那行正则, cheerio 抓取到的dom是长这样的,第一个 span 内容是日期,第二个是余票数量

所以我们要把它格式化变成这种数组,也就是 ticketList

2-3开发购票功能

首先我们在 init 方法里做个判断,如果有余票才去购票,没有余票购个毛

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代码...
 }
 //初始化
  async init(){
  let ticketList = await this.handleQueryTicket()
  //如果有余票
  if (ticketList.length) {
  //把余票传入购票逻辑方法,返回短信通知所需要的数据
   let resParse = await this.handleBuyTicket(ticketList)
  }
  }
  //查询余票的逻辑
  async handleQueryTicket(){
  // 查询余票代码...
  }
  //调用查询余票接口
  requestTicket(){
  //调用查询余票接口代码...
  }
  //购票相关逻辑
  async handleBuyTicket(ticketList){
  let year = new Date().getFullYear() //年份,
  let month = new Date().getMonth() + 1 //月份,拼接购票日期用得上,因为余票接口只返回几号
  let {
   onStationName,//起始站点名
   offStationName,//结束站点名
   lineId,//线路id
   vehTime,//发车时间
   startTime,//预计上车时间
   onStationId,//上车的站台id
   offStationId //到站的站台id
   } = this.data // 初始化的数据
  let station = `${onStationName}-${offStationName}` //站点,发短信时候用到:"宝安交通局-深港产学研基地"
  let dateStr = ""; //车票日期
  let tickAmount = "" //总张数
  ticketList.forEach(item => {
   dateStr = dateStr + `${year}-${month}-${item.day},`
   tickAmount = tickAmount + `${item.ticketLeft}张,`
  })
  var buyTicket = {
   lineId,//线路id
   vehTime,//发车时间
   startTime,//预计上车时间
   onStationId,//上车的站点id
   offStationId,//目标站点id
   tradePrice: '5', //金额
   saleDates: dateStr.slice(0, -1),
   payType: '2' //支付方式,微信支付
  }
  // 调用购票接口
   let data = querystring.stringify(buyTicket)
   let res = await this.requestOrder(data) //返回json数据,是否购票成功等等
   //把发短信所需要数据都要传入
  return Object.assign({}, JSON.parse(res.data), { queryParam: { dateStr, tickAmount, startTime, station } })
  }//购票相关逻辑
  //调用购票接口
  requestOrder(obj){
  return axios.post('http://weixin.xxxx.net/ebus/front/wxQueryController.do?BcTicketBuy', obj, {
   headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'User-Agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12A365 MicroMessenger/5.4.1 NetType/WIFI",
    "Cookie": this.cookie
   }
  })
  }
  handleInfoUser(){}//通知用户的逻辑
  sendMSg(){} //发短信接口
}

到这里,查询余票,购票这两个核心操作已经完成。

目前还剩下,如何通知用户是否购票成功。

之前我尝试过使用qq邮箱的smtp服务,抢票成功后发送邮件通知,但是我觉得吧,并不好用,主要是我没有打开邮箱的习惯,没网也收不到,所以,并没有采纳这个方案。

加上之前我注册过企业认证的公众号,腾讯云免费送了我1000条短信通知,而且短信也比较直观,所以我这里就安装腾讯云的SDK,部署了一套发短信的功能。

2-4腾讯云短信的相关内容

其实看看文档就行了,我也是copy文档,注意看短信单发那部分

cloud.tencent.com/document/pr…

如果跟我一样有企业认证的话,看快速入门这里就行了,一步步跟着操作

看下短信正文, {Number}

这些里面的数字是变量。

就是说短信的模板是固定的,但是里面有 {Number} 的内容可以自定义

调用的时候,里面的数字对应着传过去的参数数组序号,{1}代表数组[0]参数,以此类推

提交审核,审核一般很快就通过,也就是几十万毫秒吧

2-5 开发通知功能

class QueryTicket{
 constructor({ data, phoneNumber, cookie, day }) {
 //constructor代码...
 }
 //初始化
  async init(){
  let ticketList = await this.handleQueryTicket()
  //如果有余票
  if (ticketList.length) {
  //把余票传入购票逻辑方法,返回短信通知所需要的数据
   let resParse = await this.handleBuyTicket(ticketList)
  //执行通知逻辑
   this.handleInfoUser(resParse)
  }
  }

  //查询余票的逻辑
  async handleQueryTicket(){
  // 查询余票代码...
  }
  //调用查询余票接口
  requestTicket(){
  //调用查询余票接口代码...
  }
  //购票相关逻辑
  async handleBuyTicket(ticketList){
  //购票代码...
  }
  //调用购票接口
  requestOrder(obj){
  //购票接口请求代码...
  }
  //通知用户的逻辑
  async handleInfoUser(parseData){
  //获取上一步购票的response数据和我们拼接的数据
  let { returnCode, returnData: { main: { lineName, tradePrice } }, queryParam: { dateStr, tickAmount, startTime, station } } = parseData
  //如果购票成功,则返回500
  if (returnCode === "500") {
   let res = await this.sendMsg({
    dateStr, //日期
    tickAmount: tickAmount.slice(0, -1), //总张数
    station, //站点
    lineName, //巴士名称/路线名称
    tradePrice,//总价
    startTime,//出发时间
    phoneNumber: this.phoneNumber,//手机号
   })
   //如果发信成功,则不再进行抢票操作
   if (res.result === 0 && res.errmsg === "OK") {
    this.setStop(true)
   } else {
   //失败不做任何操作
    console.log(res.errmsg)
   }
  } else {
   //失败不做任何操作
   console.log(resParse['returnInfo'])
  }
  }
  //发短信接口
  sendMSg(){
  let { dateStr, tickAmount, station, lineName, phoneNumber, startTime, tradePrice } = obj
  var appid = 140034324; // SDK AppID 以1400开头
  // 短信应用 SDK AppKey
  var appkey = "asdfdsvajwienin23493nadsnzxc";
  // 短信模板 ID,需要在短信控制台中申请
  var templateId = 7839; // NOTE: 这里的模板ID`7839`只是示例,真实的模板 ID 需要在短信控制台中申请
  // 签名
  var smsSign = "测试短信"; // NOTE: 签名参数使用的是`签名内容`,而不是`签名ID`。这里的签名"腾讯云"只是示例,真实的签名需要在短信控制台申请
  // 实例化 QcloudSms
  var qcloudsms = QcloudSms(appid, appkey);
  var ssender = qcloudsms.SmsSingleSender();
  // 这里的params就是短信里面可以自定义的内容,也就是填入{1}{2}..的内容
  var params = [dateStr, station, lineName, startTime, tickAmount, tradePrice];
  //用promise来封装下异步操作
  return new Promise((resolve, reject) => {
   ssender.sendWithParam(86, phoneNumber, templateId, params, smsSign, "", "", function (err, res, resData) {
    if (err) {
     reject(err)
    } else {
     resolve(resData)
    }
   });
  })
  }
}

如果发信成功,返回 result:0

到这里,大部分需求已经完成了,还剩下一个定时任务

2-6 定时任务

也声明一个类,这里我们用到的是 schedule

// 定时任务
class SetInter {
 constructor({ timer, fn }) {
  this.timer = timer // 每几秒执行
  this.fn = fn //执行的回调
  this.rule = new schedule.RecurrenceRule(); //实例化一个对象
  this.rule.second = this.setRule() // 调用原型方法,schedule的语法而已
  this.init()
 }
 setRule() {
  let rule = [];
  let i = 1;
  while (i < 60) {
   rule.push(i)
   i += this.timer
  }
  return rule //假设传入的timer为5,则表示定时任务每5秒执行一次
  // [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56]
 }
 init() {
  schedule.scheduleJob(this.rule, () => {
   this.fn() // 定时调用传入的回调方法
  });
 }
}

2-7 多个用户抢票

假设我们有两个用户要抢票,所以定义两个obj,实例化下 QueryTicket 类

data: { //用户1
  lineId: 111130,
  vehTime: 0722,
  startTime: 0751,
  onStationId: 564492,
  offStationId: 17990,
  onStationName: '宝安交通运输局③',
  offStationName: "深港产学研基地",
  tradePrice: 0,
  saleDates: '',
  beginDate: '',
 },
 phoneNumber: 123123123,
 cookie: 'JSESSIONID=TESTCOOKIE',
 day: "17"
}
var obj2 = { //用户2
 data: {
  lineId: 134423,
  vehTime: 1820,
  startTime: 1855,
  onStationId: 4322,
  offStationId: 53231,
  onStationName: '百度国际大厦',
  offStationName: "裕安路口",
  tradePrice: 0,
  saleDates: '',
  beginDate: '',
 },
 phoneNumber: 175932123124,
 cookie: 'JSESSIONID=TESTCOOKIE',
 day: ""
}
var ticket = new QueryTicket(obj) //用户1
var ticket2 = new QueryTicket(obj2) //用户2

new SetInter({
 timer: 1, //每秒执行一次,建议5秒,不然怕被ip拉黑,我这里只是为了方便下面截图
 fn: function () {
  [ticket,ticket2].map(item => { //同时进行两个用户的抢票
   if (!item.getStop()) { //调用实例的原型方法,判断是否停止抢票,如果没有则继续抢
    item.init()
   } else { // 如果抢到票了,则不继续抢票
    console.log('stop')
   }
  })
 }
})

node index.js 运行下,跑起来了

如果他抢到票的话,我就会收到短信通知:

打开手机,看下订单信息

搞定,收工

写在最后

其实可以在此基础上还能添加更多功能,比如直接抓取登录接口获取cookie,指定路线抢票,还有错误处理啊啥的

因为这个只是我个人使用,所以只有这点功能就足够了。

如果想把它做成一个完整的项目,建议使用ts加持 ,关于ts我推荐阅读这篇JD前端写的文章

juejin.im/post/5d8efe…

希望各位能有所收获

总结

以上所述是小编给大家介绍的Node.js 实现抢票小工具 & 短信通知提醒功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • Node.js 实现抢票小工具 & 短信通知提醒功能

    要知道在深圳上班是非常痛苦的事情,特别是我上班的科兴科技园这一块,去的人非常多,每天上班跟春运一样,如果我能换到以前的大冲上班那就幸福了,可惜,换不得. 尤其是我这个站等车的多的一笔,上班公交挤的不行,车满的时候只有少部分人能硬挤上去.通常我只会用两个字来形容这种人:"公交怪" 想当年我朋友瘦的像只猴还能上去,老子身高182体重72kg挤个公交,不成问题,反手一个阻挡,闷声发大财,前面的阿姨你快点阿姨,别磨磨唧唧的,快上去啊阿姨,嗯?你还想挤掉我?你能挤掉我?你能挤掉我!我当场!把车吃

  • node.js实现博客小爬虫的实例代码

    前言 爬虫,是一种自动获取网页内容的程序.是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫而做出的优化. 这篇文章介绍的是利用node.js实现博客小爬虫,核心的注释我都标注好了,可以自行理解,只需修改url和按照要趴的博客内部dom构造改一下filterchapters和filterchapters1就行了! 下面话不多说,直接来看实例代码 var http=require('http'); var Promise=require('Bluebird'); var cheeri

  • node.js中npm包管理工具用法分析

    本文实例讲述了node.js中npm包管理工具用法.分享给大家供大家参考,具体如下: 现在安装node.js,默认就会帮我们装上了npm包管理工具,npm主要用来下载,安装,管理第三方模块. 创建一个包描述文件: npm init [-y] 查看包的信息 npm info <package-name> 查看包的版本信息 npm info <package-name> versions 安装指定的包: npm install <package-name> 默认会安装在当前

  • 150行Node.js实现的dns代理工具

    工具地址:github.com/Yi-love/dns- 安装: npm install dns-proxy-server -g 这个我觉得应该还是挺实用的一个工具.开发过程中我们需要配置IP来访问测试环境域名. 使用电脑开发测试还好,直接使用Switch hosts! , 修改域名IP即可访问特定IP的域名网站. 那么如何在手机上也尽可能容易的访问到测试环境呢? 手机如何访问到内部网络特定IP域名? 手机要访问到测试环境的域名,我们需要做的就是建立一个代理服务,然后手机通过代理服务访问测试环境

  • 用NODE.JS中的流编写工具是要注意的事项

    Node.js中的流十分强大,它对处理潜在的大文件提供了支持,也抽象了一些场景下的数据处理和传递.正因为它如此好用,所以在实战中我们常常基于它来编写一些工具 函数/库 ,但往往又由于自己对流的某些特性的疏忽,导致写出的 函数/库 在一些情况会达不到想要的效果,或者埋下一些隐藏的地雷.本文将会提供两个在编写基于流的工具时,私以为有些用的两个tips. 一,警惕EVENTEMITTER内存泄露 在一个可能被多次调用的函数中,如果需要给流添加事件监听器来执行某些操作.那么则需要警惕添加监听器而导致的内

  • 基于Node.js的JavaScript项目构建工具gulp的使用教程

    npm install gulp --save-dev 什么是gulp? gulp是新一代的前端项目构建工具,你可以使用gulp及其插件对你的项目代码(less,sass)进行编译,还可以压缩你的js和css代码,甚至压缩你的图片,gulp仅有少量的API,所以非常容易学习. gulp 使用 stream 方式处理内容.Node催生了一批自动化工具,像Bower,Yeoman,Grunt等. gulp和grunt的异同点 易于使用:采用代码优于配置策略,Gulp让简单的事情继续简单,复杂的任务变

  • 详解使用 Node.js 开发简单的脚手架工具

    前言 像我们熟悉的 vue-cli,react-native-cli 等脚手架,只需要输入简单的命令 vue init webpack project,即可快速帮我们生成一个初始项目.在实际工作中,我们可以定制一个属于自己的脚手架,来提高自己的工作效率. 为什么需要需要脚手架? 减少重复性的工作,不再需要复制其他项目再删除无关代码,或者从零创建一个项目和文件. 根据交互动态生成项目结构和配置文件等. 多人协作更为方便,不需要把文件传来传去. 思路 要开发脚手架,首先要理清思路,脚手架是如何工作的

  • 在Mac OS上安装使用Node.js的项目自动化构建工具Gulp

    安装 node.js 首先需要安装 node.js, 通常情况下,只需要到 Node.js 官网下载安装包安装就可以了.不过我可耻的失败了,弹出了如下错误: 于是我换成了 brew 大法: brew install nodejs 安装 Gulp gulp 使用 Node.js 的 npm 命令安装: npm install --global gulp 然后在项目目录中还要安装一遍: npm install --save-dev gulp 我对这步的操作比较费解.以我多年码农经验,即然全局安装过了

  • 使用Node.js和Socket.IO扩展Django的实时处理功能

    今天,我们的目标是使用Django,Redis,和Socket.IO建立一个实时的聊天室.虽然几乎所有的Web应用程序都可以建立一个聊天室的.这篇文章将以较高的水平告诉你如何将基于REST的应用程序转换成一个实时的Web应用程序的.我会使用Django创建REST的部分,实际上自由地使用任何你舒服的语言/框架均可.接下来,让我们跳进代码,先列举我们所需要的部分. 组成: Django 1.4+ Redis 2.6.x (版本可选,但是建议使用) Redis-py 2.7.x (仅当你使用Redi

  • 详解Node.js如何开发命令行工具

    前言 Node 给前端开发带来了很大的改变,促进了前端开发的自动化,我们可以简化开发工作,然后利用各种工具包生成生产环境.如运行sass src/sass/main.scss dist/css/main.css即可编译 Sass 文件. 在实际的开发过程中,我们可能会有自己的特定需求, 那么我们得学会如何创建一个Node命令行工具. hello world 老规矩第一个程序为hello world.在工程中新建bin目录,在该目录下创建名为helper的文件,具体内容如下: #!/usr/bin

随机推荐