ming_mock
ming_mock
介绍
ming_mock是什么
ming_mock是[ming_node](https://www.npmjs.com/package/ming_node)的浏览器版本,在浏览器端体验express的开发方式,专注纯前端应用,在前端与后端之间加一层ming_mock,配上丰富的web存储 与 第三方云函数,云数据库更方便的开发纯前端应用,ming_mock是[ming_node](https://www.npmjs.com/package/ming_node)的姐妹篇,强烈建议先学习使用 [ming_node](https://www.npmjs.com/package/ming_node).
mockjs对比
ming_mock中的mock是指mock服务,而不是mock数据,如果需要mock数据,建议使用[easyMock](https://www.easy-mock.com/) 或 [网易nei](https://nei.netease.com/)或者直接使用mockjs. ming_mock 相比 mockjs 体积更小(未压缩大约为mockjs 体积的六分之一,40kb,压缩后仅20kb), 支持rest风格, 拥有express相同的开放体验 , 方便的 webSql, json数据库工具等, ming_mock不擅长造假数据,但对 增 删 改 服务的mock要优于mockjs, ming_mock是专注弱化服务, 纯前端应用类型的开发,而不是用来造假数据。
因为解决查询类的mock方案很多,增删改却很少,ming_mock的内置服务很优雅的解决了增删改类的mock问题。
安装
最新稳定版 v1.9.3
项目主页 GitHub
项目地址 GitHub
npm地址 NPM
更新日志 更新日志
在线测试 https://minglie.github.io
NPM安装
ming_mock无任何第三方依赖,只是一个比较大的js文件.
# 最新稳定版
npm i ming_mock
script引入
实际应用我更多的是用script标签引入
<script src="https://minglie.github.io/js/M_mock.js"></script>
<script src="https://minglie.gitee.io/mingpage/static/js/M_mock.js"></script>
#压缩后
<script src="https://minglie.gitee.io/mingpage/static/js/M_mock-min.js"></script>
ming_mock原理
ming_mock对jquery进行动态加载判断 内部的极简jquery实现了ming_mock的0依赖,ming_mock结合easyUI是绝配,此时easyUI组件的ajax请求将会被ming_mock拦截,后面介绍如何在ming_mock不影响jquery的ajax的使用, 为了 简化调用 与 异步调用ming_mock会将app注册的所有方法都在MIO对象上再注册一遍, ming_mock同[ming_node](https://www.npmjs.com/package/ming_node)有丰富的过滤器方便公共代码抽取,公共参数的处理或拦截,为了方便调试,ming_mock将所有接口的参数用map存储,从app.reqMap 与app.resMap可以查看某一时刻每个接口最新的请求与响应数据,
http请求
ming_mock内部封装了最常用的http请求方法,无需引入其他第三方库
# url 为接口地址,callback 为回调函数, data为请求参数
# get 请求
M.fetchGet(url, callback, data);
# post请求
M.fetchPost(url, callback, data);
# post json请求
M.fetchPostJson(url, callback, data);
image.png
M.require方法
M.require是一个简易发出http get请求的方法,内部会自动识别返回的是json,文本还是,js
# 返回json
M.require("https://minglie.github.io/json/minglie.json").then(d=>console.log(d))
# 执行返回的js文件
M.require("https://minglie.github.io/json/minglie.js").then(d=>console.log(d))
# 返回文本
M.require("https://minglie.github.io/json/minglie.txt").then(d=>console.log(d))
image.png
M.doSql方法
M.doSql("select * from t_resource").then(d=>console.log(d))
或者
M.doSql("select * from t_resource",(d=>console.log(d)))
M.doSql是直接远程调用后端的app.post("/doSql"),需要后端支持,用ming_node+mysql实现
对应的服务主机地址由M.host配置,默认为空
也可以用M.doSql=M.DB().doSql覆盖
用webSql写页面
var M=require("ming_node");
var mysql = require('mysql')
myDbconfig={
"host" : "127.0.0.1",
"user" : "root",
"password" : "123456",
"port" : "3306",
"database" : "guns"
}
var app=M.server();
app.listen(8888);
var Db = {};
var pool = mysql.createPool(myDbconfig);
Db.doSql=function(sql){
var promise = new Promise(function(reslove,reject){
pool.getConnection(function(err, connection){
connection.query( sql, function(err, rows){
if(err) {
console.error(err);
reject(err);
}else{
reslove(rows);
}
});
connection.release();
});
})
return promise;
}
app.get("/",async function (req,res) {
app.redirect("/index.html",req,res);
});
app.post("/doSql",async function (req,res) {
try{
var rows= await Db.doSql(req.params.sql);
res.send(M.result(rows));
}catch (e){
res.send(M.result(e,false));
}
})
M.getParameter
M.getParameter可以方便的获取当前url上的参数,用于页面传参非常方便
M.getParameter("name")
image.png
M.urlParse
M.urlParse 实际是内部解析url参数用的,也可用于外部使用
image.png
M.fileDownload
M.fileDownload(content, filename) 用于文本文件下载
image.png
其他方法
//延时指定毫秒
M.sleep(numberMillis)
//下划线转驼峰,打印"userId"
console.log("user_id".underlineToHump())
//驼峰转下划线,打印"user_id"
console.log("userId".humpToUnderline())
//首字母变大写,打印"User"
console.log("user".firstChartoUpper())
//首字母变小写,打印"uSER"
console.log("USER".firstChartoLower())
//打印当前日期,2019-03-24
console.log(new Date().format("yyyy-MM-dd"))
//随机字符串生成
M.randomStr()
//对象转form
M.encodeURIComponentObj()
如何在ming_mock中使用$.ajax
最新版的ming_mock,我并没有强行重写 .ajax=M.ajax;
既想用ming_mock也想用$.ajax 可以用起别名的方式解决
//给apicloud用
window.$1={}
$1.ajax= $.ajax;
//给easyui用
$.ajax=M.ajax;
webpack环境中使用ming_mock
方式1(不建议)
因为这种方式需要npm 安装ming_mock 对原有项目有侵入,故不建议使用
MIO.js 用于写服务
// $ npm install ming_mock
//MIO=M.IO
import {M, app,MIO} from "ming_mock";
app.get("/listAll",function (req,res) {
console.log("params--->",req.params)
res.send("AAAAAAAA")
})
export default MIO;
index.js 引入MIO 使用
import React from 'react'
import MIO from "./MIO.js";
export default class Mockt extends React.Component {
listAll(id){
MIO.listAll({id:id}).then((u)=>{
console.log("<----u",u);
})
}
render(){
return(
<div>
<h1>ming</h1>
<button onClick={this.listAll.bind(this,77)}>点击</button>
</div>)
}
}
方式2(推荐)
index.html模版引入
为了无侵入的使用ming_mock,建议用script方式引入
模版index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://minglie.github.io/js/M_mock.js"></script>
<script>
M.ajaxInterceptorEnable()
app.get("/listAll",function (req,res) {
res.send("ww")
})
</script>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
关闭eslink检查或者使用 /* global MIO */
import React from 'react'
/* global MIO */
export default class Mockt extends React.Component {
listAll(id){
MIO.listAll({id:44}).then(d=>console.log(d))
}
render(){
return(
<div>
<h1>ming</h1>
<button onClick={this.listAll.bind(this,77)}>点击</button>
</div>)
}
}
或使用axios, ming_mock只会拦截app上注册的,也省去了全局变量问题,这种方式完全感知不到ming_mock的存在
import React from 'react'
import axios from 'axios'
/* global MIO */
export default class Mockt extends React.Component {
listAll(id){
axios.request({
method: 'get',
url: 'https://cdn.liyanhui.com/listAll?id='+id,
}).then(res => {
console.log("axios调用", res.data);
});
}
listAll1(id){
axios.request({
method: 'get',
url: 'https://www.fastmock.site/mock/489c97aee272f4fedc398579052ef5eb/ming/api/listAll1?id='+id,
}).then(res => {
console.log("axios调用", res.data);
});
}
render(){
return(
<div>
<h1>ming</h1>
<button onClick={this.listAll.bind(this,77)}>listAll1</button>
<button onClick={this.listAll1.bind(this,77)}>listAll2</button>
</div>)
}
}
普通页面使用ming_mock
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://minglie.github.io/js/M_mock.js"></script>
</head>
<body>
<button id="bt1">测试get</button>
<button id="bt2">测试rest</button>
<button id="bt3">添加</button>
<button id="bt4">查看</button>
<script>
app.get("/t1",async (req,res)=>{
console.log(req.params)
res.send(Promise.resolve(5))
})
app.get("/t2/:id/:name",async (req,res)=>{
console.log(req.params)
res.send(Promise.resolve(req.params.id))
})
app.post("addUser",async (req,res)=>{
console.log(req.params)
M.add({name:req.params.name})
res.send("add success")
})
app.get("listByPage",async (req,res)=>{
console.log(req.params)
res.send(M.listAll())
})
bt1.onclick=function(){
a=M.get("/t1?ss=77").then(d=>console.log(" bt1.onclick",d+1))
console.log(a)
}
bt2.onclick=function(){
M.get("/t2/5/zs?ss=7").then(d=>console.log("bt2.onclick",d+1))
}
a=0;
bt3.onclick=function(){
a++;
MIO.addUser({name:"zs"+a}).then(d=>console.log("bt3.onclick",d+1))
}
bt4.onclick=function(){
MIO.listByPage({}).then(d=>console.log("bt4.onclick",d))
}
</script>
</body>
</html>
内置服务
ming_mock提供了基本的增,删,改,查,分页,条件查询接口可直接使用比如添加接口MIO.add({name:"zs"}),内部随机生成一个ID,可以把这些方法覆盖掉
说明:
app.get("/xxx",(req,res)=>{})或app.post("/xxx",(req,res)=>{})会在M.IO上注册xxx方法, 用M.IO.xxx({})调用xxx方法,方法的参数必须是对象,app.get的回调函数中通过req.params拿到该对象, 这完全是express风格的写法
app.post("/add",(req,res)=>{
r=M.add(req.params);
res.send(M.result(r));
});
app.get("/delete",(req,res)=>{
M.deleteById(req.params.id);
res.send(M.result("ok"));
});
app.post("/update",(req,res)=>{
M.update(req.params);
res.send(M.result("ok"));
});
app.get("/getById",(req,res)=>{
r=M.getById(req.params.id);
res.send(M.result(r));
});
app.get("/listAll",(req,res)=>{
r=M.listAll();
res.send(M.result(r));
});
app.get("/listByParentId",(req,res)=>{
r=M.listByProp({parentId:req.params.parentId});
res.send(M.result(r));
});
app.get("/listByPage",(req,res)=>{
r=M.listByPage(req.params.startPage,req.params.limit);
res.send(M.result(r));
})
使用ming_mock分析网站接口
来个好玩的,使用ming_mock强大的ajax拦截,可以分析一些单页应用的接口调用信息,以fastMock为例,控制台输入下面脚本,
可以将接口信息发送到自己的服务器;
ajax拦截
拦截ajax请求,将请求信息发送到自己服务端
////////////////////////注入ming_mock脚本//////////////////////////////////////////
var script = document.createElement('script');
script.src = "https://minglie.gitee.io/mingpage/static/js/M_mock.js";
document.getElementsByTagName('head')[0].appendChild(script);
///////////////开启ajax拦截//////////////////////////////
M.ajaxInterceptorEnable();
//////////////发到自己服务器里///////////////////////////////
M.beforeSend=(options)=>{
M.fetchGet("http://127.0.0.1:8888/a",()=>{},options);
return true;
}
/////////////////////服务端/////////////////////////////////////////
app.get("/a", (req, res) => {
console.log(req.params)
res.send("https://c-t.work/s/7b10cb04d2754c");
})
image.png
SSE反控
浏览器开启SSE监听,服务端反控浏览器,浏览器注入axios就可以控制浏览器发送ajax了
////////////////////////注入ming_mock脚本//////////////////////////////////////////
var script = document.createElement('script');
script.src = "https://minglie.gitee.io/mingpage/static/js/M_mock.js";
document.getElementsByTagName('head')[0].appendChild(script);
////////////启动本地服务脚本接收拦截的数据///////////////////////////
curl https://gitee.com/minglie/codes/gqruda7entx53y82f6vw077/raw?blob_name=doSql.html >doSql.html
curl https://minglie.gitee.io/mi/i2.js > index.js && node index.js
app.get("/a", (req, res) => {
console.log(req.params)
res.send("https://c-t.work/s/7b10cb04d2754c");
})
if(Object.keys(M._get).indexOf("/sseServer/")==-1){
M.sseApp=M.sseServer();
app.get("/sseServer",M.sseApp)
}
app.get("/p",(req,res)=>{
console.log(req.params);
M.sseApp.send(JSON.stringify(req.params));
res.send("ok");
})
app.post("/doSql",(req,res)=>{
console.log(req.params.sql);
M.sseApp.send(req.params.sql);
res.send(M.result("ok"));
})
///////////////浏览器端SSE方式反控浏览器//////////////////////////
M.EventSource('http://localhost:8888/sseServer',function(e){
eval(e.data)
})
image.png
需要改进点
要改的问题多了以后,一起改
1. app.end() //钩子返回请求的req,否则异步调用无法将请求响应对应上