【工作】Proxy Server的优化 - 检测目标网站URL变化

  在工作中,我在组里负责一个Proxy(代理)的Module,这个Module是针对微软的Office 365的邮件门户OWA实现,工作起来后,用户访问Office 365 OWA,无需再输入Office 365的网址,只需输入我们Proxy的地址,然后我们会将请求转送到Office 365 OWA,达到用户访问的目的,并使用户的体验如同实际访问Office 365 OWA一样。

  其实我们Proxy的原理是,使用Node.js构建一个http Server,拿到client端(实际是Browser)的请求后,再将请求转给Office 365,将Office 365的返回内容Response再送给Client端,这样实现Proxy的功能

  当然实际实现过程中还有很多细节的事情,包括cookie的处理,URL的转换等,这里不细讲。

  但在工作中开发并维护此Module时,我发现一个问题,那就是虽然我们是将请求转发,但还是有很多请求我们需要特殊处理,而且有很多复杂的请求需要研究去支持,因此做为Proxy我必须知道Office 365,即目标网站都有哪些请求的类型,其实就是哪些不同的URL,不同的URL其实Path不同。

  因此我做了一个优化,因为Proxy本质是一个Http Server,因此我将客户端发来的所有请求URL打印在Log中,这样我可以在Log中收集到所有的URL,同时将该URL发送出去后收到的结果(Response Status Code)也打印在一起,这样就能知道这个URL是否处理有问题,如果返回值200,则说明OK。

  于是打印在Log中后,得到如下的Log,

 1 /___/outlook.office365.com/, 302
 2 /owa/, 302
 3 /__/login/login.srf, 200
 4 /owa/prefetch.aspx, 200
 5 /___/r1.res.office365.com/owa/prem/16.801.12.1741001/scripts/preboot.js, 200
 6 /___/r1.res.office365.com/owa/prem/16.801.12.1741001/scripts/boot.worldwide.0.mouse.js, 200
 7 /___/outlook.office365.com/GetUserRealm.srf, 200
 8 /___/r1.res.office365.com/owa/prem/16.801.12.1741001/scripts/boot.worldwide.1.mouse.js, 200
 9 /owa/ev.owa2, 200
10 /owa/ev.owa2, 200
11 /___/outlook.office365.com/, 302
12 /owa/ev.owa2, 200
13 /owa/, 302
14 /__/login/login.srf, 200
15 /owa/ev.owa2, 200
16 /owa/service.svc, 200
17 /owa/prefetch.aspx, 200
18 /___/r1.res.office365.com/owa/prem/16.807.12.1742334/scripts/preboot.js, 200
19 /owa/service.svc, 200
20 /___/r1.res.office365.com/owa/prem/16.807.12.1742334/scripts/boot.worldwide.0.mouse.js, 200
21 /owa/ev.owa2, 200
22 /owa/ev.owa2, 200
23 /owa/service.svc, 200
24 /owa/service.svc, 200
25 /___/outlook.office365.com/GetUserRealm.srf, 200
26 /___/r1.res.office365.com/owa/prem/16.807.12.1742334/scripts/boot.worldwide.1.mouse.js, 200
27 /__/login/ppsecure/post.srf, 200
28 /owa/, 302

  每一行数据,前面是URL,后面是该请求收到的Response Status Code。

  同时我自己写了一个脚本来解析Log里的数据,因为数据是重复的,需要去重以及排序。

  脚本如下:

  1 var lineReader = require('line-reader');
  2 var fs         = require('fs');
  3 
  4 var fileReadData  = "URLs.log";
  5 var fileWriteData = "result.txt";
  6 
  7 var ignoreNormalStatusCode = false;
  8 if (process.argv && process.argv[2]) {
  9     ignoreNormalStatusCode = process.argv[2];                  // development to be passed as param
 10 }
 11 
 12 console.log("ignoreNormalStatusCode: " + ignoreNormalStatusCode);
 13 
 14 // create data object
 15 var createDataObjectFromLine = function (str) {
 16     var data = str.split(",");
 17 
 18     var obj = {
 19         url: data[0].trim(),
 20         statusCode: data[1].trim(),
 21         number: 1
 22     };
 23 
 24     return obj;
 25 };
 26 
 27 // get the index in the array
 28 var indexOfObjInArray = function (array, obj) {
 29     var pos = -1;
 30     
 31     for (var i=0; i<array.length; i++) {
 32         var e = array[i];
 33 
 34         if (e.url === obj.url && e.statusCode === obj.statusCode) {
 35             pos = i;
 36             break;
 37         }
 38     }
 39 
 40     return pos;
 41 };
 42 
 43 // compare number to sort
 44 var compare_number = function (a, b) {
 45     return b.number - a.number;
 46 };
 47 
 48 // write the array's data to file
 49 var writeResultToFile = function (result, number) {
 50     var string = "";
 51     string += "Here is this URL scan result blow, \n";
 52     string += "Orignial URL number: " + number + "\n";
 53     string += "Unrepeat URL number: " + result.length + "\n";
 54     string += "------------------------------------------\n\n";
 55     string += "req url, this url's response status code (200 is ok), number statics\n";
 56     fs.appendFileSync(fileWriteData, string);
 57 
 58     for (var i=0; i<result.length; i++) {
 59         fs.appendFileSync(fileWriteData, result[i].url + ", " + result[i].statusCode + ", " + result[i].number + "\n");
 60     }
 61 };
 62 
 63 // create an array to save the urls
 64 var result = [];
 65 
 66 // count the orignial url number
 67 var number = 0;
 68 
 69 // main function
 70 lineReader.eachLine(fileReadData, function (line, last) {
 71     number++;
 72 
 73     // parse the data from every line
 74     var obj = createDataObjectFromLine(line);
 75     //console.log(obj);
 76     
 77     var pos = indexOfObjInArray(result, obj);
 78     if (pos != -1) {
 79         // this object already exists in result array
 80         result[pos].number++;
 81     }
 82     else {
 83         if (ignoreNormalStatusCode && obj.statusCode === '200') {
 84             // ...
 85         }
 86         else {
 87             // add this obj to result
 88             result.push(obj);
 89         }
 90     }
 91     
 92     if (last) {
 93         // sort the array by number
 94         result.sort(compare_number);
 95 
 96         // write the result to file
 97         writeResultToFile(result, number);
 98 
 99         // stop reading lines from the file
100         return false;
101     }
102 });

  这里使用了一个Node.js Module Line-reader,来从文件中一行行的读取数据。

  这样运行之后就可以得到解析后的结果,

 1 Here is this URL scan result blow, 
 2 Orignial URL number: 142
 3 Unrepeat URL number: 6
 4 ------------------------------------------
 5 
 6 req url, this url's response status code (200 is ok), number statics
 7 /owa/, 302, 10
 8 /___/outlook.office365.com/, 302, 5
 9 /owa/auth/15.1.225/themes/resources/segoeui-regular.ttf, 404, 3
10 /owa/auth/15.1.225/themes/resources/segoeui-semilight.ttf, 404, 1
11 /___/outlook.office365.com/favicon.ico, 302, 1
12 /owa/auth/15.1.219/themes/resources/segoeui-semilight.ttf, 404, 1

  当然以上结果是没有显示Status Code为200的URL,原因是这是Proxy处理正常的URL,暂时没必要统计与分析。

  得到结果后,显而易见,有很多404的URL,我们的Proxy并没有正确的处理,需要进一步的分析,在代码中支持。由此完成此次对产品Module的优化。

个人小感慨,工作中很多小事情,如果自己认为正确,就应坚持去做。小的优化,只要有意义,都会有大用处:-)

                                                      Kevin Song

                                                        2015-7-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏针针小站

【Soft】一个可以自定义安装Office的小工具 – OfficeTool Plus

1466
来自专栏互扯程序

跨域请求方案 终极版

现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

1633
来自专栏张善友的专栏

Visual Studio 2005的各个版本

支持正版,做DotNet开发,工具选择不二是Vistual Studio 2005,需要了解各个版本的内容相关的Licence: A:Visual Stud...

2117
来自专栏逸鹏说道

搭建个性化人脸分析系统~Face And Face++

不过多的介绍了,API调用,很简单的,看看官方文档即可~ Face++ http://www.faceplusplus.com.cn/uc_home/ 您只需要...

2816
来自专栏安恒网络空间安全讲武堂

一次对认证服务器的渗透测试

通过实施针对性的渗透测试,发现目标认证网站系统的安全漏洞,保障业务系统安全运行。

1612
来自专栏腾讯BBTeam团队的专栏

基于 Docker 分分钟搭建起 Golang 开发环境

虽然 Golang 的开发环境相对容易搭建,但是使用 docker 的优势是能方便的切换 golang 的版本,而且开发环境对开发时所使用的机器没有任何的依赖,...

2434
来自专栏西枫里博客

最简单的AJAX初级教程

    项目实现目标:验证邮箱是否已经注册 项目实现过程:用户注册页面输入完邮箱后即时提醒邮箱是否可以注册 先来看html表单代码

813
来自专栏Ryan Miao

form上传文件以及跨域异步上传

要设置了enctype属性才能上传,需要使用上传的jar包,这里使用的是cos-26Dec2008.jar, ? 关于跨域上传文件: 跨域上传文件总会报错,即使...

2866
来自专栏大内老A

.NET Core多平台开发体验[2]: Mac OS X

除了微软自家的Windows平台, .NET Core针对Mac OS以及各种Linux(RHEL、Ubuntu、Debian、Fedora、CentOS和SU...

3034
来自专栏Youngxj

迷你ASP服务器 - 服务器一键开通神器

1835

扫码关注云+社区