Chrome插件模拟HTTP请求

准备工作

http:\/\/www.google.cn\/intl\/zh-CN\/chrome\/browser\/ 下载适合你的系统的Chrome并安装

Chrome脚本

新建一个文件夹,进入这个文件夹,新建三个文件 manifest.json demo.html demo.js

manifest.json

{
    "manifest_version": 2,
    "name": "模拟HTTP请求Demo",
    "description": "以http://ssfw.xjtu.edu.cn/为例,讲解Chrome插件利用XMLHttpRequest模拟HTTP请求的方法",
    "version": "1.0.0",
    "browser_action": {
        "default_popup": "demo.html"
    },
    "permissions": [
        "https://cas.xjtu.edu.cn/*",
        "http://ssfw.xjtu.edu.cn/*"
    ]
}

demo.html

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <p>用户名:</p>
        <p><input type="text" id="username" autofocus></p>
        <p>密码:</p>
        <p><input type="password" id="password"></p>
        <p><input type="submit" id="submit" value="开始"></p>
        <ul id="output"></ul>
        <script src="demo.js"></script>
    </body>
</html>

demo.js

function output(str) {
    var lines = str.split('\n');
    for (var i = 0; i < lines.length; ++i) {
        var li = document.createElement('li');
        li.textContent = lines[i];
        document.getElementById('output').appendChild(li);
    }
}
var Request = {
    newXHR: function(callback, errMsg) {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                callback(xhr.responseText);
            }
        };
        xhr.addEventListener("error", function () {
            output(errMsg);
        }, false);
        return xhr;
    },
    get: function(url, callback, errMsg) {
        var xhr = Request.newXHR(callback, errMsg);
        xhr.open("GET", url, true);
        xhr.send();
    },
    post: function(url, form, callback, errMsg) {
        var params = [];
        for (var i in form) {
            params.push({
                name: i,
                value: form[i]
            });
        }
        Request.postParams(url, params, callback, errMsg);
    },
    postParams: function(url, params, callback, errMsg) {
        var body = [];
        for (var i = 0; i < params.length; ++i) {
            body.push(encodeURIComponent(params[i].name) + '=' + encodeURIComponent(params[i].value));
        }
        body = body.join('&');
        var xhr = Request.newXHR(callback, errMsg);
        xhr.open('POST', url, true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(body);
    }
};
var Regex = {
    match: function(regexp, str, errMsg) {
        var matches;
        if ((matches = regexp.exec(str)) === null) {
            output(errMsg);
        }
        return matches;
    },
    matchAll: function(regexp, str) {
        var result = [];
        var matches;
        while ((matches = regexp.exec(str)) != null) {
            result.push(matches);
        }
        return result;
    }
};
var Demo = {
    htmlToText: function(html) {
        return html.replace(/<[\s\S]*?>/g, ' ').replace(/&nbsp;/g, ' ').replace(/[\s\x0B\xC2\xA0]+/g, ' ').trim();
    },
    username: '',
    password: '',
    main: function(username, password) {
        Demo.username = username;
        Demo.password = password;
        Request.get('http://ssfw.xjtu.edu.cn/logout.portal', function(body) {
            Request.get('https://cas.xjtu.edu.cn/logout', function(body) {
                var matches
                if (matches = Regex.match(/注销成功/g, body, '初始化失败')) {
                    output('初始化成功');
                    Demo.loadCas();
                }
            }, '初始化失败');
        }, '初始化失败');
    },
    loadCas: function() {
        Request.get('https://cas.xjtu.edu.cn/login?service=http%3A%2F%2Fssfw.xjtu.edu.cn%2Findex.portal', function(body) {
            var matches
            if (matches = Regex.match(/name="lt" value="(.*?)"[\s\S]*?name="execution" value="(.*?)"[\s\S]*?name="_eventId" value="(.*?)"/g, body, '获取登录凭证失败')) {
                var lt = matches[1];
                var execution = matches[2];
                var _eventId = matches[3];
                output('获取登录凭证成功');
                Demo.loginCas(lt, execution, _eventId);
            }
        }, '读取CAS登录页面失败');
    },
    loginCas: function(lt, execution, _eventId) {
        Request.post('https://cas.xjtu.edu.cn/login?service=http%3A%2F%2Fssfw.xjtu.edu.cn%2Findex.portal', {
            username: Demo.username,
            password: Demo.password,
            code: '',
            lt: lt,
            execution: execution,
            _eventId: _eventId
        }, function(body) {
            var matches
            if (matches = Regex.match(/url=(.*?)"/g, body, '用户名或密码错误')) {
                var ssfwUrl = matches[1];
                output('登录CAS成功');
                Demo.loginSsfw(ssfwUrl);
            }
        }, '登录CAS失败');
    },
    loginSsfw: function(ssfwUrl) {
        Request.get(ssfwUrl, function(body) {
            var matches
            if (matches = Regex.match(/<li style="color:#fff;font-weight:bold;">(.*?)<\/li>/g, body, '获取师生服务首页失败')) {
                var hello = matches[1];
                output('登录师生服务系统成功');
                output(hello);
                Demo.listCourse();
            }
        }, '登录师生服务系统失败');
    },
    listCourse: function() {
        Request.get('http://ssfw.xjtu.edu.cn/index.portal?.p=Znxjb20ud2lzY29tLnBvcnRhbC5zaXRlLmltcGwuRnJhZ21lbnRXaW5kb3d8ZjExNjF8dmlld3xub3JtYWx8YWN0aW9uPXF1ZXJ5', function(body) {
            var matches
            if (matches = Regex.match(/<tbody>([\s\S]*?)<\/tbody>/g, body, '解析课程列表失败')) {
                var table = matches[1];
                output('读取课程列表成功');
                var courses = Regex.matchAll(/<tr[\s\S]*?>([\s\S]*?)<a href="(.*?)">(.*?)<\/a>/g, table);
                for (var i = 0; i < courses.length; ++i) {
                    var course = courses[i];
                    var desc = Demo.htmlToText(course[1]).replace(/ /, '\t');
                    var action = course[3];
                    if (action !== '评教') {
                        output('================================================================================');
                        output(desc);
                    } else {
                        var url = 'http://ssfw.xjtu.edu.cn/index.portal' + course[2];
                        try {
                            Demo.loadCourse(url, desc);
                        } catch (e) {
                            output(e.message);
                        }
                    }
                }
            }
        }, '读取课程列表失败');
    },
    loadCourse: function(url, desc) {
        var msgPrefix = '================================================================================\n' + desc + '\n';
        Request.get(url, function(body) {
            var matches;
            if (matches = Regex.match(/post" action="(.*?)"/, body, msgPrefix + '获取提交网址失败')) {
                var url = 'http://ssfw.xjtu.edu.cn/index.portal' + matches[1];
                var params = [];
                var errMsg = msgPrefix + '解析课程失败';
                params.push({ name: 'wid_pgjxb', value: Regex.match(/wid_pgjxb" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'wid_pgyj', value: Regex.match(/wid_pgyj" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'type', value: '2' });
                params.push({ name: 'sfytj', value: Regex.match(/sfytj" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'pjType', value: Regex.match(/pjType" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'wid_pjzts', value: Regex.match(/wid_pjzts" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'status', value: Regex.match(/status" value="(.*?)"/g, body, errMsg)[1] });
                params.push({ name: 'ztpj', value: '很好' });
                params.push({ name: 'sfmxpj', value: Regex.match(/sfmxpj" value="(.*?)"/g, body, errMsg)[1] });
                var trs = Regex.matchAll(/教师评价([\s\S]*?)<\/tr>/g, body);
                for (var i = 0; i < trs.length; ++i) {
                    var tr = trs[i][1];
                    params.push({ name: 'zbbm', value: Regex.match(/zbbm" type="hidden" value="(.*?)"/g, tr)[1] }, errMsg);
                    var matches = Regex.match(/(wid_.*?)" type="hidden" value="(.*?)"/g, tr, errMsg);
                    params.push({ name: matches[1], value: matches[2] });
                    matches = Regex.match(/(qz_.*?)" type="hidden" value="(.*?)"/g, tr, errMsg);
                    params.push({ name: matches[1], value: matches[2] });
                    var scoreMatches = Regex.matchAll(/(pfdj_.*?)"  value="(.*?)"/g, tr);
                    var j = parseInt(Math.random() + 0.5);
                    params.push({ name: scoreMatches[j][1], value: scoreMatches[j][2] });
                }
                params.push({ name: 'pgyj', value: '很好' });
                params.push({ name: 'actionType', value: '2' });
                Demo.evalCourse(url, desc, params);
            }
        }, '读取课程信息失败');
    },
    evalCourse: function(url, desc, params) {
        var msgPrefix = '================================================================================\n' + desc + '\n';
        Request.postParams(url, params, function(body) {
            output(msgPrefix + '评教成功');
        }, msgPrefix + '评教失败');
    }
};
document.getElementById('submit').onclick = function() {
    try {
        Demo.main(document.getElementById('username').value, document.getElementById('password').value);
    } catch (e) {
        output(e.message);
    }
};

运行插件

然后在Chrome中访问 chrome:\/\/extensions ,点击 加载已解压的扩展程序... ,选择刚才新建的那个文件夹即可。

现在浏览器右上角会有一个插件的图标,点击图标,弹出一个页面,即可使用。

代码说明

这个Chrome插件使用的XMLHttpRequest模拟HTTP请求、正则匹配,其他原理同Node.js。

初始化时执行了两个注销操作,目的是排除浏览器原有的Cookie的影响。

注意:由于js的异步非阻塞特性,多门科目评教共同进行,容易对服务器产生较大压力(某种意义上的DoS攻击),有时会出现评教失败现象。要解决这个问题可以重试几次提交,或者做成阻塞型,本示例不再继续讨论。

results matching ""

    No results matching ""