分类 教程分享 下的文章

引言

相信大家平常在开发过程中,经常会遇到此类需求。危险操作(如删除,退出登录)往往需要弹框提示给用户二次确认一下。本文介绍的是,如何使用js方法装饰器,封装二次确认弹框操作,增加小伙伴的开发效率。

装饰器介绍

2020-08-03T08:01:10.png

装饰器是对类、函数、属性之类的一种装饰,可以针对其添加一些额外的行为。详细使用,自行百度!

常规手段

view

<div class="bg-white flex justify-center">
    <div class="btn-primary" @click="clickMe">点我</div>
</div>

js

clickMe() {
    uni.showModal({
      title: "点击提示",
      content: "你确定要点我?",
      success: (res) => {
        if (res.confirm) {
          console.log("点我干啥");
        }
      },
    });
 }

效果展示

装饰器点击效果

装饰器写法

confirm.js

function confirm(message: string, title: string, cancelFn = function() {}) {
  return function(target: any, name: string, descriptor: any) {
    const originFn = descriptor.value;
    descriptor.value = function(rest: any) {
      uni.showModal({
        title: title,
        content: message,
        success: (res) => {
          if (res.confirm) {
            originFn.apply(this, rest);
          }
        },
      });
    };
  };
}

main.js

@confirm("你确定要点我?","点击提示")
  clickMe() {
    // uni.showModal({
    //   title: "点击提示",
    //   content: "你确定要点我?",
    //   success: (res) => {
    //     if (res.confirm) {
    //       console.log("点我干啥");
    //     }
    //   },
    // });
    console.log("点我干啥");
  }

效果展示

装饰器点击效果

2020-07-17T08:19:34.png

引言

干前端工作,大致离不开三大任务:切图,对接口,写页面逻辑。说到对接口,那肯定是离不开网络请求API的封装的。我将网络请求的封装模式大致分为三个派系:

  1. 无拘无束派 (只封装请求根地址,想咋请求就咋请求,最强的封装就是不封装)
  2. 拦截请求派 (使用一个拦截器配置请求行为和一些错误的拦截处理)
  3. 接口集成派(使用一个或多个文件,统一管理所有请求,约定不允许使用文件中未定义的接口)。

我属于第三个派系,首先介绍一下各派的风格

各派风格

无拘无束派在快速成型方面略有优势,自由度也相对较高,但是维护起来并不容易,遇到接口改版的时候一部小心就会遗漏。

img

拦截请求派属于较优雅的一个派系,没有太多多余的内容,剩下的内容都是为解决问题而生。一般使用一个第三方请求库(如axios,flyio等)完成封装。大致像是这样

import { FlyError, FlyResponse } from "flyio";
const Fly = require("flyio/dist/npm/wx");
let fly = new Fly();
// 配置请求根地址
fly.config.baseURL = process.env.VUE_APP_BASE_URL;
// 配置响应拦截器
fly.interceptors.response.use(
   // 如果请求成功,即请求状态码2xx
  (response: FlyResponse) => {
    // 并且操作成功
    if (response.data.success) {
       // 返回响应数据体
      return Promise.resolve(response.data);
    } else {
    // 请求成功,但是操作失败,提示后端返回的msg,并抛出错误
      uni.showToast({
        icon: "none",
        title: response.data.msg,
      });
      return Promise.reject(response.data);
    }
  },
  // 如果请求失败,即状态非2xx
  (err: FlyError) => {
    console.error(err);
    // 状态码为401,即跳转登录
    if (err.status === 401) {
      uni.reLaunch({
        url: "/pages/login",
      });
      return;
    }
    // 其他错误状态码,就先弹个框吧
    uni.showModal({
      title: err!.request!.url + "接口状态" + err.status,
      content: "错误原因:" + err.engine.response.msg,
    });
    return Promise.reject(err);
  }
);

然后使用的时候就直接采用第三方的请求,如fly.get(),fly.post

现在来介绍我所属的派系,我比上面更极端一点,除了封装请求拦截器暴露POST,GET外,还将所有的接口集中到一个API文件(太多了就按类型拆分,如user,shop,setting)

我的实现

基本请求文件http.ts,已引入上文提及的拦截器

function GET(url: string, params = {}): Promise<ApiResponse> {
  let config = {
    headers: {
      Authorization: store.state.token,
    }
  };
  return fly.get(url, params, config);
}
function POST(url: string, params = {}): Promise<ApiResponse> {
  let config = {
    headers: {
      Authorization: store.state.token,
    }
  };
  return fly.post(url, params, config);
}
export { GET, POST };

api.ts,负责集成Api

import { GET, POST } from "./http";
export default class Api {
  /**
   * 登录接口
   * @param params phone,password
   */
  login(params: object) {
    return POST("/user/login", params);
  }
  /**
   * 获取账户下所有店铺
   */
  getShop() {
    return POST("/shop/getShopListByUserId");
  }
  /**
   * 获取首页数据总览
   * @param params {shopId}
   */
  getOverview(params: {}) {
    return POST("/user/homepage/statistics", params);
  }
  /**
   * 根据店铺Id获取二级分类
   * @param params {shopId}
   */
  getCommodityType(params: {}) {
    return POST("/cnccommodity/commodity_type/by_shop", params);
  }
  /**
   * 分页获取商品列表
   */
  getCommodityList(params: {}) {
    return POST("/cnccommodity/commodity_by_page", params);
  }
}

然后将Api文件,挂载到Vue的原型链。

import API from "./plugins/fly/api";
Vue.prototype.$api = new API();

在组件中使用

 this.$api.login(this.loginForm).then((res) => {
 console.log(res)
 })

这样高度封装的好处是,任何一个接口要改内容,或者自定义功能,都可以只维护Api文件就行了。假设有一需求,要在获取商品之后提示用户”恭喜发财“,而这个接口又在多个页面中使用,我可以只做如下修改即可。

 /**
   * 分页获取商品列表
   */
  getCommodityList(params: {}) {
    showToast("恭喜发财")
    return POST("/cnccommodity/commodity_by_page", params);
  }

这是一个荒诞的需求,但是如果需求是部分请求超过1s就显示加载中呢?或者部分接口需要显示后端返回的msg呢?我可以这样做。

api.ts

updatePw(params: object) {
    return Post("/adminmanage/updatePassWard", params, true);
},

http.ts

export async function Post(api: string, params = {}, needToast = false) {
  let data = await axios.post(api, params);
  if (data.success && needToast) {
    Message.success(data.msg);
  }
  return data;
}

为了应对频繁更改的需求,我真是煞费苦心。

Typescript的加持

上面一直在说接口封装的事情,好像对Typescript只字未提。虽然上面都使用了typescript但是都只是铺垫,真正让代码编写柔润丝滑的是声明文件。

原型Api的声明

上面我们已经将api挂载到vue的原型,但是typescript的作用并未完全发挥。typescript有两个强大的作用,1. 减少代码出错率 2. 提高代码书写效率。要启用ts强大的语法提示功能,我们需要先写一个d.t文件。

vue-property.d.ts

import Vue from "vue";
import Api from "./plugins/fly/api";
declare module "vue/types/vue" {
  interface Vue {
    $api: Api;
  }
}

该文件的作用就是将Vue原型链上的$api类型设置为Api Class, 接下来我们来一起看看它的效果。

typescript推导api

Vs code贴心的语法提示,从注释提示到参数。无与伦比的代码护航能力几乎能让你无脑写请求。

响应结构体的声明

人不能满足现状,光有请求推导可还不够。我们还要让它推导响应结构体。假设项目后端返回的响应结构如下

{
    "code": 200,
    "success": true,
    "msg": "操作成功",
    "result": {
    }
}

我们再创建一个响应的d.ts文件

index.d.ts

interface ApiResponse {
  /**
   * code: 响应状态码
   */
  code: number;
  /**
   * success: 操作是否成功标准
   */
  success: boolean;
  /**
   * msg: 请求的附带信息
   */
  msg: string;
  /**
   * result: 请求返回结果
   */
  result: Object | any;
}

同时声明接口请求返回为ApiResponse

function GET(url: string, params = {}): Promise<ApiResponse> {
  let config = {
    headers: {
      Authorization: store.state.token,
    }
  };
  return fly.get(url, params, config);
}
function POST(url: string, params = {}): Promise<ApiResponse> {
  let config = {
    headers: {
      Authorization: store.state.token,
    }
  };
  return fly.post(url, params, config);
}
export { GET, POST };

看看语法提示效果

ts推导响应体

同时如果有分页,还可以声明分页的结构体。总之,声明文件写得好,效率提高绝对少不了。

后记

ts给我一种以前写C++的感觉,需要先写声明文件.h然后在写.cpp,这样做的好处是约束你的代码,让你的代码更规范。不过,缺点就是声明文件有种给自己找事的感觉,不过我依旧强烈建议在前端项目下使用ts。这在后期的维护是绝对有利的,而且也并非所有文件都需要写声明文件,要不要写声明文件,取决于你的实现方式。比如本文中的Api文件就没写声明文件,照样可以类型推导,语法提示。祝我早日实现无脑编码~

为什么需要?

微信小程序里面页面与自定义组件的区别较大,而页面的可复用程度太低了。要么就是跳转页面,要么就是copy代码。如果我们要增加代码的可复用性,就可以借用Vue组件的思想,将页面改写为自定义组件。

结构对比

两者的视图文件,样式文件没有什么区别。主要区别最大的就是js文件,我们首先来看一下两者的结构。

page.js

page({
  // 数据内容
  data:{},
  // 生命周期函数
  onLoad(){},
  // 一些自定义函数
  someMethods(){}
})

componet.js

componet({
  // 预设属性
  properties: {},
  // 数据内容
  data: {},
  //组件所在页面生命周期
  pageLifetimes: {},
  // 生命周期函数-挂载
  attached: function() {
    // 在组件实例进入页面节点树时执行
  },
  // 生命周期函数-卸载
  detached: function() {
    // 在组件实例被从页面节点树移除时执行
  },
  // 自定义函数写结构里面
  methods:{
    someMethods(){}
  }
})

我们可以看到,两者的基本相似,大同小异。所以改写起来就特别方便啦~

  1. 将page改为componet
  2. 适配生命周期函数,例如将页面onLoad()函数改写为组件的attached()函数
  3. 将自定义函数someMethods()写到Componet的methods里面

效果展示

列表顺序加载动画

本文会讲述如何使用scss/sass在微信小程序中实现列表顺序加载的动画。

所用的css特性

CSS animations

CSS animations 使得可以将从一个CSS样式配置转换到另一个CSS样式配置。动画包括两个部分:描述动画的样式规则和用于指定动画开始、结束以及中间点样式的关键帧。

相较于传统的脚本实现动画技术,使用CSS动画有三个主要优点:

  1. 能够非常容易地创建简单动画,你甚至不需要了解JavaScript就能创建动画。
  2. 动画运行效果良好,甚至在低性能的系统上。渲染引擎会使用跳帧或者其他技术以保证动画表现尽可能的流畅。而使用JavaScript实现的动画通常表现不佳(除非经过很好的设计)。
  3. 让浏览器控制动画序列,允许浏览器优化性能和效果,如降低位于隐藏选项卡中的动画更新频率。

css animations的属性和子属性见https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Animations/Using_CSS_animations#%E9%85%8D%E7%BD%AE%E5%8A%A8%E7%94%BB

可主要分为两大部分,动画的实现形式和动画的属性规则。

以下仅列出本文所用的属性。

animation-timing-function

animation-timing-function 规定动画的速度曲线。

速度曲线

animation-delay

顾名思义,设置动画的持续时间,单位秒

animation-fill-mode

animation-fill-mode 属性规定动画在播放之前或之后,其动画效果是否可见。

animation-fill-mode

使用keyframes定义动画序列

keyframes就是一个描述关键帧的属性,通过使用@keyframes建立两个或两个以上关键帧来实现。每一个关键帧都描述了动画元素在给定的时间点上应该如何渲染。

因为动画的时间设置是通过CSS样式定义的,关键帧使用percentage来指定动画发生的时间点。0%表示动画的第一时刻,100%表示动画的最终时刻。因为这两个时间点十分重要,所以还有特殊的别名:from和to。这两个都是可选的,若from/0%或to/100%未指定,则浏览器使用计算值开始或结束动画。

示例

@keyframes list {
        0% {
            transform: scale(0);
        }

        100% {
            transform: scale(1);
        }
    }

如上代码所示,定义了一个@keyframe名字叫list,在动画开始时使用缩放0%,结束时缩放100%。那么它在整个动画的过程中,便会根据浏览器的性能展示一个从0%-100%渐变的动画。是不是根据有点意思?当然,你也可包含设置任何额外可选的关键帧,描述动画开始和结束之间的状态,比如45%。

animation.gif

至此我们已经实现了组件显示时逐渐放大的效果

所用的scss特性

以下为简介,详细内容请转至官方文档

嵌套规则 (Nested Rules)

scss/Sass允许将一个 CSS 样式嵌套进另一个样式中,内层样式仅适用于外层样式的选择器范围内。

引用父选择器:&

你可以 & 字符来明确地表示插入指定父选择器。

变量: $(Variables: $ )

以美元符开头,可当变量使用。

@mixin混入指令 (Mixin Directives)

混入(mixin)允许您定义可以在整个样式表中重复使用的样式,而避免了使用无语意的类(class),比如 .float-left。混入(mixin)还可以包含所有的CSS规则,以及任何其他在Sass文档中被允许使用的东西。
他们甚至可以带arguments,引入变量,只需少量的混入(mixin)代码就能输出多样化的样式。

插值:#{}(Interpolation: #{})

你可以通过 #{} 插值语法在选择器和属性名中使用 SassScript 变量:

@for

顾名思义,循环,要留意一下tothrough的区别

引用混合样式:@include (Including a Mixin: @include)

实现方式

wxml文件

<view class="list__item">
<view>...</view>
</view>

编译前的scss/sass

    .list {
        &__item {
            animation: list 1s ease both;
        }
    }

    @keyframes list {
        0% {
            transform: scale(0);
        }

        100% {
            transform: scale(1);
        }
    }

    @mixin item($num) {
        $waitTime: ($num)*0.2;
        animation-delay: #{$waitTime}s;
    }

    @for $i from 1 through 7 {
        .list__item:nth-child(#{$i}) {
            @include item($i);
        }
    }

less版

// list动画
    .list__item {
        animation: list .8s ease both
    }

    @keyframes list {
        0% {
            transform: scale(0);
        }

        100% {
            transform: scale(1);
        }
    }

    .generate-columns(7);

    .generate-columns(@n, @i: 1) when (@i =< @n) {
        .list__item:nth-child(@{i}) {
            animation-delay: @i * 0.2;
        }

        .generate-columns(@n, (@i + 1));
    }

编译后的css

.list__item {
  -webkit-animation: list 1s ease both;
          animation: list 1s ease both;
}
@-webkit-keyframes list {
0% {
    -webkit-transform: scale(0);
            transform: scale(0);
}
100% {
    -webkit-transform: scale(1);
            transform: scale(1);
}
}
@keyframes list {
0% {
    -webkit-transform: scale(0);
            transform: scale(0);
}
100% {
    -webkit-transform: scale(1);
            transform: scale(1);
}
}
.list__item:nth-child(1) {
  -webkit-animation-delay: 0.2s;
          animation-delay: 0.2s;
}
.list__item:nth-child(2) {
  -webkit-animation-delay: 0.4s;
          animation-delay: 0.4s;
}
.list__item:nth-child(3) {
  -webkit-animation-delay: 0.6s;
          animation-delay: 0.6s;
}
.list__item:nth-child(4) {
  -webkit-animation-delay: 0.8s;
          animation-delay: 0.8s;
}
.list__item:nth-child(5) {
  -webkit-animation-delay: 1s;
          animation-delay: 1s;
}
.list__item:nth-child(6) {
  -webkit-animation-delay: 1.2s;
          animation-delay: 1.2s;
}
.list__item:nth-child(7) {
  -webkit-animation-delay: 1.4s;
          animation-delay: 1.4s;
}

列表顺序加载动画效果展示

参考资料

使用CSS动画
CSS3 animation-timing-function 属性
sass中文文档

引言

熟悉uni-app的人应该都知道,uni-app并未对微信小程序云函数(本文统称云函数)进行相应的适配。但是,如果我们在某些业务场景的下需要使用云函数呢?我们知道,云函数可以复制到微信开发者工具,这样的话我们不得不每次编译一次就手动复制一次,不得不说麻烦至极。本文就问题做出以下解决方案。

本文环境

  1. Hbuilder X

Hbuilder X版本

  1. 微信开发者工具

微信开发者工具版本

创建云函数目录

首先,我们需要在uni-app项目文件夹下,创建一个云函数目录,路径随意,我这里是functions。然后先随便在里面放一些文件,这里以new_file.css为例。

修改manifest.json

在uni-app根目录下,修改manifest.json中的微信小程序项,结构如下

"mp-weixin" : {
        /* 小程序特有相关 */
        "appid" : "wxd7de467f6e6cf741",
        "cloudfunctionRoot": "./functions/", // 这一行就是标记云函数目录的字段
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    }

编写vue.config.js

  1. 我们在项目根目录创建vue.config.js文件
  2. 写入以下内容(如路径不一样请做相应适配)
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
    configureWebpack: {
        plugins: [
            new CopyWebpackPlugin([{
                from: path.join(__dirname, 'cloudFunctions'),
                to: path.join(__dirname, 'unpackage/dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env
                    .UNI_PLATFORM, 'cloudFunctions')
            }])
        ]
    }
}
  1. 编译运行

发现提示如下内容

提示内容

说明未安装copy-webpack-plugin插件,我们手动安装一下。

npm install -save copy-webpack-plugin
TIPS: 截至2020.6.4, uni-app暂不支持copy-webpack-plugin 6.0版,请安装5.0版

安装copy-webpack-plugin

然后编译运行,发现微信开发者工具里面出现以下内容。

微信开发者工具里面的内容


截止目前,已打通Hbuilder X到微信开发者工具的自动复制,即已解决本文的核心内容。以下为进一步测试。

创建云函数

我们在云函数根目录上右键,在右键菜单中,可以选择创建一个新的 Node.js 云函数,我们将该云函数命名为check。开发者工具在本地创建出云函数目录和入口 index.js 文件,同时在线上环境中创建出对应的云函数。创建成功后,工具会提示是否立即本地安装依赖,确定后工具会自动安装 wx-server-sdk。我们会看到以下内容。

创建好后将其同步复制到uni-app项目,即可为以后自动同步行方便,又可避免在输出文件夹中云函数的意外丢失。至此,相关文件编写工作转至Hbuilder X,云函数上传部署依旧在微信开发者工具。

云函数模板内容

编写云函数

默认的云函数只是一个返回用户基本数据的内容,我们将其修改至满足我们的业务需求,以内容安全云调用为例。

在云函数文件中写入以下内容

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

// 云函数入口函数
exports.main = async(event, context) => {
  try {
    console.log('待检测文本:' + event.content);
    let result = await cloud.openapi.security.msgSecCheck({
      content: event.content
    })
    console.log('result:' + JSON.stringify(result));

    if (result && result.errCode.toString() === '87014') {
      return {
        code: 300,
        msg: '内容含有违法违规内容',
        data: result
      }
    } else {
      return {
        code: 200,
        msg: 'ok',
        data: result
      }
    }

  } catch (err) {
    if (err.errCode.toString() === '87014') {
      return {
        code: 300,
        msg: '内容含有违法违规内容',
        data: err
      }
    }
    return {
      code: 400,
      msg: '调用security接口异常',
      data: err
    }
  }
}

权限申明

云函数config权限声明

如上图,在函数目录下,创建一个config.json,文档说会自动创建,但是我实际操作时未自动创建。config.json内容如下。

{
    "permissions": {
        "openapi": [
            "security.msgSecCheck"
        ]
    }
}

然后在函数目录右键,上传并部署。

小程序调用云函数

App.vue

<script>
  export default {
    onLaunch() {
      wx.cloud.init();
    }
  }
</script>

index.vue

let res = await wx.cloud.callFunction({
          name: 'checkText',
          data: {
            "content": this.displayString
          }
        })
        if (res.result.code != 200) {
          uni.showModal({
            title: "温馨提示",
            content: "你所输入的内容可能含有违法违规内容,不支持进行下一步操作"
          })
          return
        }

效果展示

微信图片_20191022110949.png

百度定义

DNS欺骗就是攻击者冒充域名服务器的一种欺骗行为。

百度原理

如果可以冒充域名服务器,然后把查询的IP地址设为攻击者的IP地址,这样的话,用户上网就只能看到攻击者的主页,而不是用户想要取得的网站的主页了,这就是DNS欺骗的基本原理。DNS欺骗其实并不是真的“黑掉”了对方的网站,而是冒名顶替、招摇撞骗罢了。

为什么会有DNS欺骗?

其实DNS欺骗不能叫欺骗,为什么这么说,因为dns解析采取就近原则,意思是说谁能先帮我解析我就听谁的。给你解析一个假的ip就是欺骗。例如本来www.baidu.com 对应ip是202.16.25.78    ,你在本地架设一个dns服务器将www.baidu.com 解析为192.168.100.2 , 这不就等于骗了别人吗。【1】

如何防护DNS欺骗?

360安全卫士号称可以,防护DNS欺骗
2019-07-03T02:36:57.png
经实测:DNS防护并未防护成功,而局域网防护却可以找出攻击者IP,和伪装后的DNS服务器IP。但是却无法实际性的抵御DNS攻击。
2019-07-03T12:32:20.png

被攻击后如何恢复?

  1. 改host文件。
  2. 指定DNS服务器。
  3. 开代理

如何发起攻击?

申明:以下目的只有一个就是学习技术,如果有人利用本文技术进行非法操作带来的后果都是操作者自己承担,和本文以及本文作者没有任何关系。

本文环境

win10 + vmware + kali-linux-2019-02
其实新一代的win10预览版升级的WSL2已经兼容了很多linux网络设备相关操作了,比如Nmap之类的。但是因为WSL的网络连接方式只有NAT模式,这样就不利于我测试了,所以我使用的是vmware虚拟机运行KALI,网络模式如下
2019-07-03T06:21:37.png

1. 查看网络

ifconfig

2019-07-03T06:24:03.png

由上图可以看到,有两个网络连接,一个eth0有线连接,一个lo无线设备。因为我装了外置网卡,所以虚拟机下有无线连接。
确保你已经连上你想要攻击的目标网络。
2019-07-03T06:26:36.png
因为我使用的是有线连接,所以我接下来的操作都是在eth0上操作。

2. 修改DNS文件

vim /etc/ettercap/etter.dns

2019-07-03T06:28:59.png

熟悉host文件的小伙伴一看就明白,这一条条都是DNS解析记录嘛。

我们在文件最后追加

* A 192.168.0.131

这句话的意思就是,将所有的域名都解析到IP地址为192.168.0.131的主机上。而这个是我的kali的本机ip。

3. 发起DNS欺骗

ettercap -Tq -i eth0 -M arp:remote -P dns_spoof /// ///

参数就不解释啦--help就都知道啦,我只讲思路。

2019-07-03T06:34:45.png

如上图DNS欺骗就已经开始了。

4. 局域网断网攻击

因为上面我将所有的域名地址都解析到了,我的本机IP。而我本地却没有搭建任何web服务,这个时候如果用户访问网站都会出现如下图效果。
2019-07-03T06:37:21.png

由于浏览器DNS缓存的问题,此方式可能短期内对近期访问过的网站不起作用。

5. 针对特定网站攻击

假如我对百度很有意见,我见不惯别人使用百度。

vim /etc/ettercap/etter.dns

那么我可以将dns文件修改为

*.baidu.com A 192.168.0.131

这样只要别人访问百度就会出现
2019-07-03T06:37:21.png

但是这样有个问题,这样攻击久了,是个人都会觉得奇怪。百度这么大的公司怎么会长时间访问不了呢?

6. 针对特定网站搭建空壳网站

为了避免被别人怀疑,我需要搭建一个空壳百度。

  • 首先浏览器下载百度首页。
  • 搭建一个静态网站,展示百度首页。
  • 执行DNS欺骗

然后就会出现以下效果
2019-07-03T07:05:08.png
为了区别是我搭建的,我把百度一下改成了小度一下。
但是细心的小伙伴会发现,左上的https变成了红色不安全字样,这是因为我搭建的web服务签不了www.baidu.com证书的原因。我只是随便签了一个HTTPS证书。

7. 针对某些局域网认证上网的账号密码钓鱼

截止目前,我们已经做到了断掉了局域网的网络,并将所有网站跳转至搭建网站的效果。看到这里,有没有觉得很熟悉?对了,妥妥的需认证网络的操作。
接下来我们以家里蹲大学的校园网认证系统为例,模拟一个搭建钓鱼校园网认证系统并盗取密码的过程。

  • 第一步:扒下家里蹲大学认证首页的网页文件

2019-07-03T07:27:53.png

  • 第二步:搭建钓鱼网站
  • 第三步:拦截局域网所有DNS解析请求,将所有网站解析到搭建的钓鱼网站。
  • 第四步:修改表单信息的提交地址
  • 第五步:写一个接收表单数据的接口

8. 模拟中招过程

陈小美吃完饭,到图书馆坐下,想刷会微博。突然发现,微博上不去了。显示的是
2019-07-03T08:51:32.png
对于这个界面,小美一点都不陌生。因为这是即将学校的校园网的认证系统的前兆。小美熟练的输入账号密码。一点也不知道接下来即将发生什么。
2019-07-03T09:20:29.png
然而,在小美提交账号密码的那一刻,我收到了一个好东西。
2019-07-03T10:08:28.png
接下来就是开始表演的时候,我用她的账号登录了以下网站。

  • 学籍信息,看到了她的照片,知道了她的手机号,QQ号,名字,家住何处,家里多少成员,家庭年收入多少,哪个高中毕业。以此来筛选是否符合择偶要求。
  • 教务处,知道了她大几,什么专业,学分绩点多少,选修了什么课程。以此来判断是否有共同的兴趣爱好。
  • 图书馆,了解他是否热爱阅读,喜欢什么类型的书籍。来判断是否处得来。
  • 饭卡消费记录,以此来判断她的消费水平,以及她喜欢在哪里吃饭。来判断是否养得起。
  • 校园论坛,了解她的世界观与价值观,以及是否是个谈吐优雅的女子。判断能否一起面对生活。

然后:我加了她的QQ,以小师弟寻求帮助的名义加了她,先混个脸熟。接着,我开始在QQ空间发一些符合她世界观和价值观的说说,以此来获取她的共鸣。我知道她可能不看QQ空间,但是我保持着几乎每周一次的个性签名更新。并且在个性签名更新后的1-12个小时内随机(使用C++生成随机数)找她聊关于她在图书馆所看书籍的一些想法(我猜她会感兴趣)。这样我可以保证无论她使用哪个平台哪个版本的QQ都可以看到,在她心中种下一颗我是一个与她灵魂相似的人的种子。学期末,我知道她选了什么课程,这门课程什么时候考试。这是一门大学恶梦课程,我知道她肯定要去图书馆复习,所以我借共同复习借口约了她去图书馆。之后的时间,我间歇性的约她去图书馆,因为我深知要想被女生喜欢,千万不可表现过度。一定要保持一个较为舒适的距离,为这颗种子慢慢浇水。但在不约她的时间里,我也会在食堂“偶遇”她,之所以说是“偶遇”,因为我已经对她的饮食习惯分析得一清二楚。几次过后,她会觉得和我好有缘。而其实。。。偶然之中必有必然。我甚至比她还要了解她的习惯,喜好。她觉得我很贴心^-^,但是我到现在还没有告诉她,为什么我们会遇见。看似上天的安排,实则是我的安排。我不去想是否会赢得爱情,既然钟情于玫瑰,就要勇敢的吐露真诚。或许,这便是一种成熟吧!

分享一些个人常用的效率软件

navicat——功能强大的数据库连接软件

navicat界面预览

推荐理由:极具现代化又功能强大的数据库管理软件,远摔那些上古时代软件好几条街

frp——配置容易支持多方式(dns,ssh,http..)的内网穿透软件

frp功能一览

推荐理由:配置只需几秒即可上线,而且支持多种协议,常备测试的好软件。不过需要自己有服务器,不过如果你没有的话。。。。那你还写什么代码?!

Xshell——优雅方便的远程ssh连接软件

Xshell官方介绍

enter description here

推荐理由:Xshell自诩业界最强shh客户端,我觉得它一点也没有夸大,无论从美观还是功能性来看,它都能配上业界最强。

Xftp——同上,优雅的sftp连接软件

index-xftp-3.png

因为和xshell是一家,个人觉得也是个非常方便的软件。

360压缩——无广告的轻便的压缩软件

这个就不介绍了,除了给你右键加了很多菜单外(新版可以改成一个),应该是目前我用过的最舒服的压缩软件了。

typecho——轻量级的博客软件

2019-07-01T13:25:57.png

别看官网极其简陋,但是性能确是极强,再给它换套皮肤,也是可以很好看的,我的博客就是typecho搭建的。

新媒体管家——全网平台文章同步软件(chrome插件)

2019-07-02T10:11:39.png

看,一键全网发布,多爽

V2ray——隐藏身后的**软件(ws+tls+cdn)

这是个啥软件?我不知道。。。自行百度?

宝塔面板——小白都能轻松管理服务器的软件

2019-07-02T10:14:21.png

AppNode——免费优雅的多服务器管理软件

2019-07-02T10:15:14.png
2019-07-02T10:15:39.png

WeGesture——windows下的一款鼠标手势快捷键

2019-07-02T10:16:27.png
我一般用它来管理虚拟桌面,单显示器穷尽所能

小书匠——性感优雅的markdown编辑软件

小书匠

VScode——好看且实用的代码编辑器

2019-07-02T10:19:56.png

Hbuilderx——现在一般用来写微信小程序

2019-07-02T10:21:24.png

用得最爽的代码提示,有种想我所知的感觉

光影魔术手

一个可以一键排版各种证件照的工具

光影魔术手智能排版

ScreenToGif

录屏转gif

RaiDirver

挂载网盘变本地磁盘

附加一些常用网站

墨刀——原型图设计网站

稿定设计——海报设(piao)计(qie)软件

七牛云——国内优秀的内容存储平台

cloudFlare——保护并加速任何线上网站

justmysocks

3d66.com-破解软件集群

remove.bg——快速移除背景图片

引言

首先看一张最终效果图

终端.PNG

大致思路

使用win10的linux子系统,安装zsh,默认切换zsh终端。(什么鬼,这和装虚拟机有什么不一样?放心,不一样的,慢慢看)

为什么要需要它?

  1. cmd太丑,cmder略慢,然后就是命令的不统一性。
  2. 一个好看的终端可以让程序员变得开心又愉快。
如下

截图.PNG

准备工作

  1. win10内部版本16215.0以上
  2. 打开win10开发人员模式
  3. 勾选控制面板>程序>启用windows功能>linux子系统
  4. 重启
  5. 打开应用商店>搜索linux, 选择你喜欢的linux发行版安装,我选的是ubuntu18.04,如果卸载了应用商店可以自行百度开启方式

-- 至此:linux系统安装成功

在linux子系统中需要做的操作

在开始栏运行ubuntu

或者win+R,键入wsl运行。

安装zsh

sudo apt-get install zsh

设置默认shell

chsh -s /bin/zsh

安装oh-my-zsh

sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"

(可选项)修改主题

nano ~/.zshrc
我的修改如下

2019-03-12T07:02:46.png

让bash每次打开自动执行zsh

重新打开终端窗口,我们目前的效果是这样的。

ssh1.PNG

然后就会发现,这丫的,这怎么跟我的win10保持文件共享呢?

让linux子系统默认打开win10用户根目录

  1. 首先找到C\\windows\\system32\\wsl.exe,复制到你的win10用户根目录。
  2. 再为根目录的bash.exe创建快捷方式发送到桌面。
  3. 运行
看,好神奇

2019-03-12T07:14:16.png

可是,,,难道每次我运行命令都要回到桌面启动?而且就不能像ubuntu那样ctrl + alt + T打开?

为适应win10的一些配置

  1. 右键点击桌面快捷方式,选择快捷键,同时按ctrl + alt + T设置快捷键。
  2. 桌面右键>选择查看>取消勾选显示桌面图标
测试ctrl + alt + T,我可能是为数不多的秀win10桌面的程序员:) (好像还是没有linux的好看?)

2019-03-12T07:23:44.png

在vs code里配置默认终端为wsl.exe。效果展示

2019-03-12T07:27:41.png

结束语

因为截图会变模糊,实际效果比这好看的多,嗯,又多了一个装逼的东西。

想达到本文效果,需使用wepy框架。不了解wepy?转https://tencent.github.io/wepy/index.html

什么是async/await?

在最新的ES7(ES2017)中提出的前端异步特性:async、await。
async顾名思义是“异步”的意思,async用于声明一个函数是异步的。而await从字面意思上是“等待”的意思,就是用于等待异步完成。也就是我们平常所说的异步等待。不过需注意await只能在async函数中使用

为什么需要async/await?

在async/await之前,我们有三种方式写异步代码

1. 嵌套回调

其中思想就是,a函数执行完了得到的结果后在执行b。
形如

wx.getSetting({
      success(res) {
        console.log(res.authSetting['scope.userLocation']);
        if (!res.authSetting['scope.userLocation']) {
          wx.authorize({
            scope: 'scope.userLocation',
            fail(res) {
              Toast('无法获取位置,采用默认排序');
            }
          });
        } else {
          wx.getLocation({
            type: 'wgs84',
            success(res) {
              _this.setData({ location: res });
              console.log('您的位置信息:', res);
            },
            fail() {
              Toast('无法获取位置,采用默认排序');
            }
          });
        }
      }
    });
上面的代码你不用看,就会感觉。这啥东西?乱七八糟的。这就是嵌套回调。很不巧,原生微信小程序开发就是这样的。

2. 以Promise为主的链式回调

所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。形如
var p1 = new Promise((resolve, reject) => {
 setTimeout(resolve, 1000, 'done');
 })
p1.then(data=>{
 console.log(data); // done
})

如果你的函数够多的话,那么就会一直then()下去。

为了优雅,Promise提供了一个方法Promise.all([p1,p2,p3]) ,用于将多个Promise实例,包装成一个新的Promise实例。接收的参数是一个数组,p1、p2、p3都是Promise对象
分两种情况:
  1. p1、p2、p3的状态都是resolve的时候,Promise.all的状态才会变成resolve;
  2. 只要p1、p2、p3中有一个的状态为reject,那么Promise.all的状态就会变成reject;

所以我们可以用Promise.all()来解决多个异步依赖调用。

3. 使用Generators

function *main() {
    var x = yield 1;
    var y = yield x;
    var z = yield (y * 2);
}
上面代码中的每一条语句都会按顺序一个一个地执行。Yield关键字标明了代码中被阻塞的点(只能被generator函数自己阻塞,外部代码不能阻塞generator函数的执行),但是不会改变*main()函数中代码的执行顺序。这段代码很简单!

但是,这三种写起来都还是不够优雅,ES7做了优化改进,async/await应运而生,async/await相比较Promise 对象then 函数的嵌套,与 Generator 执行的繁琐(需要借助co才能自动执行,否则得手动调用next()), Async/Await 可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。

示例
async a(){};
const b = await a();

这样做的好处?

唔,你不觉得一个优雅的代码就该是这样吗?好吧,其实这样更容易符合我们平常的思维逻辑

回到本文的题目

在wepy1.4.1以后的版本(之前的版本都是默认开启的),默认不支持async/await,需要用户手动加入,方法如下:

进入项目根目录,安装runtime包

npm install wepy-async-function --save

修改wepy.config.js加入runtime配置

        babel: {
            "presets": [
                "env"
            ],
            "plugins": [
                "transform-export-extensions",
                "syntax-export-extensions"
            ]
        }

在app.wpy中引入引入runtime包

import 'wepy-async-function'; 

在app.wpy中使API promise化

重写构造函数,使其支持async/await。
export default class extends wepy.app {
    constructor () {
        super();
        this.use('promisify');
    }
}

重启编译

wepy build --no-cache

使用示例

在wepy框架官方文档中已说明,对所有的微信小程序都支持async/await操作。只需将形如wx.getuserInfo改写为wepy.getuserInfo即可
async userInfoAsync() {
    const _this = this;
    const data = await wepy.getSetting(); //获取设置数据
    if (data.authSetting['scope.userInfo']) { //判断是否有获取用户信息的权限
      await wepy.login(); //登录
      let data = await wepy.getUserInfo();//获取用户信息
      _this.userInfo = data.userInfo;//采用wepy框架修改过后的功能,支持直接赋值数据绑定
      _this.$apply(); //在async的函数中,必须主动执行`$apply()`来进行脏数据检查
    }
  }
async onShow() {
    this.userInfoAsync(); //调用async函数
  }
以上代码实现了异步同步用户userInfo的功能

参考文献:

  1. 使用Promise链式调用解决多个异步回调的问题
  2. 关于js的callback回调函数以及嵌套回调函数的执行过程理解
  3. ES6 Generators并发
  4. ES7前端异步玩法:async/await理解
  5. 理解 JavaScript 的 async/await
  6. Async/await学习
  7. 浅谈async/await
  8. wepy项目中使用async await

本文实践平台:腾讯云(qcloud.com)

首先我们来看看腾讯云官方的解决方案示意图
0.png

看懂了吗?看没看懂都没关系我们开始走一遍就好了。大致步骤如下:

  1. 购买腾讯云微信小程序解决方案
  2. 部署 mysql 实例到云数据库
  3. 部署网站到服务器,使网站外网可访问
  4. 将网站与数据库连接起来
  5. 配置 SSL 证书,使网站可 https 访问
  6. 构建负载均衡,使用户可以通过负载均衡的方式访问
  7. 制作服务器镜像,将可成功访问的服务器复制
  8. 新建 N(N>0)台服务器,将服务器重装为自定义镜像
  9. test

详细如下:

  • 购买腾讯云微信小程序解决方案
  1. 进入腾讯云官网(https://www.qcloud.com)

  1. 选择解决方案>微信小程序解决方案

就选择 3 元新购活动吧,我已经购买过了,就不再这儿演示怎么购买了。

  1. 购买成功之后腾讯云会下发资源。

succeed:此过程成功标志为资源下发成功,以及收到如下站内信。
  • 部署 mysql 实例到云数据库

  1. 根据上图所提供的地址,使用数据库连接工具(如 Navicat)连接数据库进行数据传输。_

  1. 数据传输_

succeed:此过程的成功标志为,在远程数据库中可查看到相应的表和数据
  • 部署网站到服务器,使网站外网可访问
  1. 首先我们对腾讯云下发的 demo 服务器进行重装系统(精神洁癖,不重装不舒服)_
注:不重装的话,网站的根目录在/data/release/php_weapp_demo > \_ > * > > >
我这儿装的是 centOS 6.5。版本不同可能会对应的软件安装方式不同。 2.*为服务器安装 apache\_ #安装 apache
root@localhost ~]# yum -y install httpd

开机自启动

[root@localhost ~]# chkconfig httpd on

启动 httpd 服务

[root@localhost ~]# service httpd start

安装 apache 一些扩展

root@localhost ~]# yum -y install httpd-manual mod_ssl mod_perl mod_auth_mysql

succeed:此步骤成功标志为访问http://localhost  或 http://本机IP  ,应该会看到 Apache 的测试页面

这里需要注意 iptables 的设置哦。

安装 php[root@localhost ~]# yum -y install php php-mysql

安装 php 常用扩展

[root@localhost ~]# yum search php
[root@localhost ~]# yum -y install gd php-gd gd-devel php-xml php-common php-mbstring php-ldap php-pear php-xmlrpc php-imap
 ### 重启 httpd 服务,这一步很重要
[root@localhost ~]# service httpd restart
然后,我们提供 php 页面,测试
[root@localhost ~]# cd /var/www/html/
[root@localhost html]# vi index.php
<?php
    phpinfo();
<php>
succeed:此步骤成功标志为,出现传说中的 phpinfo()界面

后记:不知不觉,已经写了有这么多了!本来想一篇写完的,看了一下可能篇幅实在是太长了。先这样吧。敬请期待下一篇吧!

到了这步的时候,你只需要把网站源代码(例如博客,或者自己开发的网站)上传到目录/var/www/html/就好了。windows 操作系统可以利用工具(如 winscp)上传。觉得有用的就点赞收藏一下吧。谢谢大家的支持。