6

分割线以下是原来写的,其实mock的原理非常简单,就是拦截请求“转发”到本地文件,所谓转发,其实就是读取本地mock文件,并以json或者script等格式返回给浏览器。之前的实现方式有一个问题,因为mock文件是require进来的,所以每当修改mock文件后,需要重启服务,其实换个思路,我们从文件里面读数据不久行了么?

//mockAPI.js

var fs = require('fs');
var path = require('path');

var mockbase = path.join(__dirname, 'mock');

var mockApi = function(res, pathname, paramObj, next) {
    switch (pathname) {
        case '/api/vote':
            var data = fs.readFileSync(path.join(mockbase, 'vote.json'), 'utf-8');

            // res.setHeader('Content-Type', 'application/json');
            res.setHeader('Content-type', 'application/javascript');
            res.end(paramObj.callback + '(' + data + ')');
            return ;

        case '/api/getUserInfo':
            var data = fs.readFileSync(path.join(mockbase, 'getUserInfo.json'), 'utf-8');
            res.setHeader('Content-type', 'application/javascript');
            res.end(paramObj.callback + '(' + data + ')');
            return ;
        case '/api/apply':
            var data = fs.readFileSync(path.join(mockbase, 'apply.json'), 'utf-8');
            res.setHeader('Content-type', 'application/javascript');
            res.end(paramObj.callback + '(' + data + ')');
            return ;
        default:
            ;
    }
    next();
};

module.exports = mockApi;
//gulpfile.js
var mockApi = require('./mockApi');
...
gulp.task('webserver', function() {
    gulp.src('./app')
        .pipe(webserver({
            ...
            middleware: function(req, res, next) {
                var urlObj = url.parse(req.url, true),
                    method = req.method,
                    paramObj = urlObj.query;
                // mock数据
                mockApi(res, urlObj.pathname, paramObj, next);
            }
        }));
});

知道了原理后,无论是ajax还是jsonp,你想怎么mock就怎么mock。另外可以利用webserver的proxies选项把请求代理到线上(通过代理解决跨域),这样就不用本地的mock文件,而是直接请求线上或beta环境的接口了。


最近在使用gulp构建前端项目,这个基于node流并崇尚“编程而非配置”的工具立马让我爱上了它。因为之前使用公司的fekit,所以在使用gulp时就会想和fekit去比较,看看fekit的功能用gulp如何实现。fekit在前后端分离上做得非常好,基本能让前端开发人员脱离后端环境进行开发,其中很重要的一个功能就是接口数据的mock。简单地讲,就是转发ajax请求到本地的json(或mockjson)文件,这样我们在代码里写真实的url(而不是写一个本地的json文件地址),然后借由fekit转发到本地的json文件,这样就轻松实现了接口的mock。

在这次项目中,我同样有这样的需求,举个例子,我需要把/api/orders转发到/mock/orders.json,前一个是我实际请求后端的地址(一个restful接口),后一个是我本地的json文件。

在使用gulp的时候,有一个叫gulp-mock的模块,可惜它是把mockjson转化为json的,不能实现反向代理式的转发。另一个模块,proxy-middleware,可以实现反向代理,但就我使用来看,是目录级别的,比如配置/api/orders转发到/mock/orders.json,它会说/mock/orders.json/不是一个目录。

在几番折腾各种搜索外加中途放弃的情况下,我看了下gulp-webserver(我在gulp中使用的webserver模块)的源码,发现它开放了一个middleware,通过这个middleware我们可以拦截请求并处理(这个过程其实就是node http模块做的事情)。因为gulp-webserver的文档并没有介绍这个参数的使用,所以之前我虽然知道但并没有去尝试,后来阅读源码发现gulp-webserver使用的其实是connect这个模块,而这个模块有关于middleware的使用说明。到这里,问题算是暂时性解决了。

gulpfile.js

gulp.task('webserver', function() {
    gulp.src('./market')
        .pipe(webserver({
            livereload: true,
            directoryListing: {
                enable:true,
                path: 'market'
            },
            port: 8000,
            // 这里是关键!
            middleware: function(req, res, next) {
                var urlObj = url.parse(req.url, true),
                    method = req.method;
                switch (urlObj.pathname) {
                    case '/api/orders':
                        var data = {
                            "status": 0,
                            "errmsg": "", 
                            "data": [{}]
                        };
                        res.setHeader('Content-Type', 'application/json');
                        res.end(JSON.stringify(data));
                        return;
                    case '/api/goods':
                        // ...
                        return;
                    case '/api/images':
                        // ...
                        return;
                    default:
                        ;
                }
                next();
            }
        }));
});

这里还只是简单的把返回的数据写在了gulpfile.js里,实际上我们也可以把数据放在文件里,然后require进来,此外我们也能通过method区分处理不同请求。

这个也许不是唯一的解决办法,但这次探索给了我不少启示,这也是我在前面写那么多“废话”的原因。作为一个成熟的开发人员,在遇到问题特别是通过搜索手段(包括询问他人、看github的issue等)仍难以获取有效信息的情况时,我们需要深入问题本身(比如看源码、探究实现原理),做探索问题的先驱者。


animabear
1.2k 声望42 粉丝

动漫控 | IT boy | 前端攻城湿 | 有点宅 | 懒得吐槽 | 小迷茫 | Adiaos | 喜欢好产品


引用和评论

0 条评论