美文网首页
web接口测试微百科

web接口测试微百科

作者: Null_ice | 来源:发表于2019-03-12 20:16 被阅读0次

00 序 动态web技术演进史

动态web技术演进史

web技术发展的历史,可以说也是整个互联网发展的历史;我们从前端和后端(服务端)两个维度,来简单的谈一下动态web技术的演进史。

初级的静态web时代

在最初的静态资源时代,主要由前端主导页面的展示,此时服务端仅仅是静态web服务器,可以理解为只是一个承载html等页面资源的容器。而我们的页面,也仅仅是像报纸一样的静态展示,内容的修改编辑都是靠对服务器上文件的修改编辑。此时的请求仅仅是对静态资源的请求,甚至谈不上是一个接口。

ajax和cgi主导下的动态web技术拉开序幕

随着ajax,局部动态刷新技术,和cgi,通用网关接口的出现,标志着web时代正式进入动态时代。
ajax可以允许js为局部页面提供请求服务,并更新浏览器的dom对象;而cgi作为web服务器和外部应用程序的通信标准,让服务器可以通过cgi执行外部程序,这两个技术,再加上到现在仍然流行的mvc设计模式,产生了无数经典的web产品。

在这个背景下,请求一个cgi程序往往是/xxx/xx.cgi的形式,这种请求才真正的算是一个接口,因为他包含了具有逻辑意义的程序。

再往后,cgi程序(请注意cgi程序和cgi是两个概念)因为低下的效率问题被时代抛弃,新的继任者是各种cgi的“升级”选项,例如php的FastCGI,python的wsgi等等。

而我们的前端技术,也藉由nodejs技术产生了质的飞跃,产生了诸如reactjs,vue等伟大的前端框架。

nodejs让前后端分离走向极致

传统的非前后端分离式开发,是由后端渲染页面,通过一个基础的html作为模板,将动态内容由后端动态生成,再整个传输到服务器,最终展示在浏览器上,因此,当你请求一个这种技术下的接口时,你会发现,接口的response里,存了整个html信息。这种开发方式虽然存在诸如方便seo,单独开发节约人员等优点,但是,也存在诸如可维护性,可复用性差,前后端混搭,开发效率低等问题。

而前后端分离的开发则解决了这些问题,尤其是nodejs和react的出现,更将前后端分离几乎做到了极致,在这开发方式下,前后端由独立的服务运行,前端负责渲染和传输数据到服务端,后端负责处理数据并返回给前端,因此,在这种技术下,当你请求一个接口时,只会看到后端返回的数据(一般是json)。

后端架构演进,从单体应用架构到微服务

当网站的流量不多的时候,我们往往只需要部署一个单应用节点,将所有功能、服务都部署在一起以节约硬件成本,这就是单一应用架构;

而随着流量的逐渐加大,提升单机硬件带来的成本越来越高,效率却越来越低,此时,我们可以将系统业务拆分成几个互不关联的系统,分别部署在各自机器上,以划清逻辑并减小压力,这就是垂直应用架构;

当我们的业务越来越多、应用系统也越来越多时,自然的,我们会发现有些功能已经不能简单划分开来或者划分不出来。此时,可以将公共业务逻辑抽离出来,将之组成独立的服务Service应用 。而原有的、新增的应用都可以与那些独立的Service应用交互,以此来完成完整的业务功能,这就是分布式服务架构;

随着敏捷开发、持续交付、DevOps理论的发展和实践,以及基于Docker等轻量级容器(LXC)部署应用和服务的成熟,微服务架构开始流行,逐渐成为应用架构的未来演进方向。通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队敏捷缴费,应用的交付周期将缩短,运维成本也将大幅下降;这就是微服务架构。

引用文档:

微服务理论之一:应用架构演进史

Dubbo介绍前篇------单一应用框架、垂直应用框架、分布式应用框架、流动计算框架,及RPC的简介

动态web技术(二) --- CGI

【Web开发原理】web发展历史

01 HTTP协议和RESTFUL

HTTP,DNS,TCP,IP组成的一条龙式网络服务

当我们访问一个web页面的时候,比如http://www.xxxx.com/xxx,其实是这么一个过程。

首先,客户端通过DNS(域名解析系统)解析出目标网页的真实服务器(ip)地址;

其次,tcp三次握手建立连接,通过http协议针对这个地址发出请求报文;

然后,tcp协议分割请求报文,利用ip协议找到对方,把报文安全的传给目标端;

再然后,当对方利用tcp协议收到并重组成完整的报文后,会再利用http协议处理报文,解析出请求目的,交由对应的请求资源后,再把结果回传给请求端。

以上就是HTTP,DNS,TCP,IP组成的一条龙式网络服务,下面我们针对这个过程里的一些点详细分析。

HTTP的报文内容

一个请求的url包含了协议类型,目标地址,目标端口和资源位置以及有时候可能附带的参数。

简单来说,一个请求可以包括两个部分(或者更细的划分为4个部分),即请求头和请求体;在请求头中,我们重点关注以下字段:

method:主要描述了请求的请求方法,用的比较多的肯定是get和post,更多一点的还有head、delete、option、connect等等。

User-Agent:主要用于标识浏览端的信息,比如你通过chrome访问,带去的User-Agent就是chrome的信息。(为什么关注这个字段?因为某些接口限制User-Agent类型的请求)

Referer:主要标识请求来源,表示你是从哪个地方过来访问的。(为什么关注这个字段?因为某些安全设置,接口的访问会限制Referer来源)

Connection:标识是否保持连接(keep-alive)

cookie:标识用户识别标志。(因为http是无状态连接)

以上是请求头需要关注的字段,接下来我们来看看响应头里需要关注的字段:

access-control-allow-origin:标识了服务端是否接受以及接受哪些域可访问,标识为*表示接受跨域请求。

status:响应码,标识了服务端对请求的结果状态,常见的响应码分为2xx系列(成功响应),3xx系列(重定向),4xx系列(找不到请求资源),5xx系列(服务端错误)。

restful开发风格:post和get能否互换?

上面介绍了请求头里的请求方法,常见的比如post和get,都可以给服务端传递参数,那么他们有什么区别呢?post和get,能否互换?

从请求方法的客观定义上来说,post和get可能是以下区别,post支持的传输长度更长,而且不显式的传递参数,更加安全;而get直接用url传递参数,传输长度也有限制,那么如果在双方的交集里,post和get能否互换?

或者更加大的问一个问题,为什么,要有这么多的请求方法?我通过delete方法传参删除一个资源,和我通过post方法传参删除一个资源,不都可以达成目的吗?那为什么还要有这么多种的方法?

这里就需要说回http的设计者了,他设计这么多方法的本意,是想大家都通过一个统一规范的开发方式,即restful,来操作资源。

restful的开发方式,是面向资源的开发方式,什么叫面向资源的开发方式?就是以url为资源的唯一标识符,各种请求方法都只是对该资源的操作,在这样的开发方式下,可以规范url的格式,提高对于接口的理解。

因此,如果你的项目是遵循restful风格的项目,那么,post和get的互换就是不合适的。

熟悉restful并不是要求你的项目一定要遵从这个风格,但是,这对你对请求方法的原始设计用意是有帮助的。

02 抓包工具和mock server

Https和CA证书

在说抓包工具之前,我们有必要说明一下https的运行机理,因为这关系到那些使用中间人攻击方式的抓包工具的原理。

我们都知道为了安全才推广https,那么它安全在哪呢?http时代,所有传输的都是明文的,这就意味着,如果你的流量经由第三方中转,那么你的所有传输内容都是直接暴露给第三方的。

为了解决这个问题,需要对传输的内容进行加密处理,但是因为我们的web应用和客户端是一对多的关系,如果只采用同一种对称加密(即加密解密使用一个密钥)算法,那么无异于没有加密;如果对每个客户端采用不同的对称加密算法通信,又要面临对协商加密算法的过程加密的问题,否则如果你在和客户端协商加密的过程里被第三方拦截,同样会泄露加密方式。

加密协商过程就用到了非对称加密,也就是公私钥机制,私钥可以解所有公钥加密的内容,公钥只能解私钥加密的内容。这样,服务端拥有一个私钥,客户端请求服务端的公钥将协商过程加密,然后传给服务端,服务端再用私钥解密,就完成了使用非对称加密加密协商过程,但这样还有个问题,就是如果中间人拦截了公钥请求,使用自己伪造的公钥替换服务端回传的公钥,这样客户端使用伪造的公钥加密内容,中间人就可以使用伪造的公钥的私钥解密内容。

为了防止中间人对服务端公钥的拦截伪造,所以引入了第三方权威机构的ca证书概念,也就是权威第三方使用它的私钥,加密服务端的公钥,这样,如果客户端可以使用权威第三方的公钥解密出服务端的公钥,就说明这个服务端公钥不是被伪造的;为了区别第三方给不同公司的加密,所以ca上还存在有验证编码,可以算出这个ca是给谁加密的,方便客户端校验证书正确性。

回到我们的抓包工具上,很多抓包工具(例如fiddler),如果你想抓取https的内容,那么第一步你需要信任一个CA证书,结合以上https的原理,你应该知道这是为什么了吧,这个信任的ca就是为了假装自己是第三方机构,从而骗过浏览器,这就是中间人攻击类型的抓包工具的原理。

截断,伪造和mock

mock的定义,简单来说就是提供虚拟数据,在一些不好构造数据的场景里提高开发或者测试效率;在这里以fiddler为例,简述如何进行接口mock。

fiddler手动截断并替换请求/响应值

简单的完成请求截断非常简单,只要在fiddler的底栏这里点击一下All Process按钮右侧的空白格,向上的图标代表请求截断,向下的图标代表响应截断。

当拦截模式开启时,fiddler的请求列表界面会相应的把请求或者响应的通信标上一个拦截标志,这代表这条通信被截断了,此时你可以在fiddler的右侧工具栏对这条通信的信息进行修改,然后点击run to completion,就可以让你修改的内容发送给服务端或者返回给客户端。

fiddler手动构造请求发送

通过上面的教学,我们已经可以截断和伪造请求/响应了,但有时候我们只想要一个修改过的全新的请求,而不是一直靠截断来完成请求的构造,这时候我们可以利用fiddler右侧的Composer工具来完成。

只需要在通信列表里,将你想改造的请求拖进composer的界面,就拿到了这个请求的基本数据,当你改动完毕后,点击Execute就可以直接发送该请求。

fiddler自动替换响应值

之前的截断和替换,都是手动的,有没有办法可以自动完成截断和替换呢?毕竟一条一条请求手动处理太麻烦了。

这里我们用到AutoResponder,他可以根据你制定的规则,自动的替换接口的返回值。

轻量级的mock server方案:anyproxy

上面讲的是基于fiddler的接口mock,但如果想搭建一个mock服务fiddler还是有点稍显笨重,这里介绍一个更加轻量级的mock服务搭建方案:anyproxy。

anyproxy是阿里出品的一个基于nodejs环境的代理服务器,他可以跨操作系统运行,并且支持自定义mock规则,项目也是开源的,因此适合做一个轻量级的mock server。

anyproxy需要nodejs的环境(最好是v8.0版本的),装好npm后只需要执行npm install -i anyproxy即可完成安装。

anyproxy代理https请求

同fiddler一样,anyproxy代理https请求需要首先信任他的ca证书,默认的代理接口是127.0.0.1:8001,我们可以在浏览的代理设置里,将lan的代理这样设置。

设置完毕后,通过cmd执行 anyproxy -i命令,就可以在127.0.0.1:8002这个地址观察到抓取的流量信息。

使用rule.js制定mock规则

anyproxy的rule.js文件使用js语言,制定了五个节点作为mock点,分别是:
beforeSendRequest(发送请求前);
beforeSendResponse(返回响应前);
beforeDealHttpsRequest(启用https解析);
onError(请求过程发生错误时);
onConnectError(与服务器的连接产生错误)。

我们在写好rule文件后,可以在命令行通过选项 --rule 来指定规则文件,这里我们以一个小例子来说明rule的编写。

任务:在百度搜索“深圳明源怎么样”时,把结果改为“666666666666”

以下是rule.js文件的内容:

'use strict';

module.exports = {

  summary: 'the default rule for AnyProxy',

  /**
   *
   *
   * @param {object} requestDetail
   * @param {string} requestDetail.protocol
   * @param {object} requestDetail.requestOptions
   * @param {object} requestDetail.requestData
   * @param {object} requestDetail.response
   * @param {number} requestDetail.response.statusCode
   * @param {object} requestDetail.response.header
   * @param {buffer} requestDetail.response.body
   * @returns
   */
  *beforeSendRequest(requestDetail) {
    return null;
  },


  /**
   *
   *
   * @param {object} requestDetail
   * @param {object} responseDetail
   */
  *beforeSendResponse(requestDetail, responseDetail) {
     //只做演示,很多细节未考虑~~~
    if(requestDetail.url.indexOf("https://www.baidu.com/s?")>-1)
    {   
        const url_parmeters = requestDetail.url.split("s?")[1].split("&");
        //console.log(url_parmeters);
        for (var i=0;i<url_parmeters.length;i++){
            //console.log(url_parmeters[i]);
            if (url_parmeters[i].indexOf("wd=")>-1){
                const wd = url_parmeters[i].split("=")[1];
                if(wd === "%E6%B7%B1%E5%9C%B3%E6%98%8E%E6%BA%90%E6%80%8E%E4%B9%88%E6%A0%B7"){                   
                    const newResponse = responseDetail.response;
                    newResponse.body = '66666666666666666666';
                    console.log("will change~~~~~~~");
                    return new Promise((resolve, reject) => {
                        resolve({ response: newResponse});
                        });
                    };
                };
                //console.log("will show the wd is :    ~~~~~~~~~");
                //console.log(wd);
            };
            
        //console.log(requestDetail);
    }else {
        console.log("not baidu!!!");
    };
    
    return null;
  },


  /**
   * default to return null
   * the user MUST return a boolean when they do implement the interface in rule
   *
   * @param {any} requestDetail
   * @returns
   */
  *beforeDealHttpsRequest(requestDetail) {
   return true;
  },

  /**
   *
   *
   * @param {any} requestDetail
   * @param {any} error
   * @returns
   */
  *onError(requestDetail, error) {
    return null;
  },


  /**
   *
   *
   * @param {any} requestDetail
   * @param {any} error
   * @returns
   */
  *onConnectError(requestDetail, error) {
    return null;
  },
};

可以看到我们的规则写在beforeSendResponse方法里,主要是在服务端返回响应的时候,如果是我们规定的请求,那么就替换这个请求对应返回值的内容。

接口mock和fuzz测试

先介绍一下fuzz(模糊)测试的概念,fuzz测试主要藉由构造大量的随机或者半随机数据,对目标系统做输入,从而发现未知的bug或者漏洞。
现实中,系统可能只对程序预想的处理数据做兼容处理,而对一些异常的,不常规的值没有处理或者处理的不好,我们在构造异常数据时,如果是一个接口一个接口做,工作量太大了,因此,我们可以借由mock server,配置我们的mock规则,从而实现对接口层面的fuzz测试。

接口mock和性能测试

接口mock为何会和性能测试搭上线?实际上,由于性能测试场景的复杂,组成一个场景的接口或者接口内部,往往是存在依赖关系的,而如果我们只想得到某一部分的性能值,就不能把这种依赖关系的性能数据算进去,这时候就需要对这种依赖关系做mock,不真实等待请求结果而是直接返回构造数据,这样就避免了依赖关系的速度性能对待测部分的性能数据的污染。

接口mock的应用场景总结

通过上面的介绍,我们来总结一下接口mock的应用场景:

在前端开发的工作中,可以通过提前mock接口返回值,提高开发效率;

在某些场景例如支付中,可以mock请求和响应值,看是否存在校验漏洞导致系统数据异常

在模糊测试中,可以通过mock server构造随机返回值,观察系统的健壮程度;

在性能测试中,可以通过mock接口设置挡板,避免性能数据被污染;

。。。。。。

参考资料:

在 anyproxy 上做 mock 和 fuzz 测试

https原理通俗了解

anyproxy官网

浅谈HTTPS以及Fiddler抓取HTTPS协议

相关文章

  • web接口测试微百科

    00 序 动态web技术演进史 动态web技术演进史 web技术发展的历史,可以说也是整个互联网发展的历史;我们从...

  • 微信小程序接口测试时appid为空如何解决

    一、web接口测试和app/微信小程序接口测试的区别 web接口一般是通过浏览器访问,app接口是通过手机端访问的...

  • 接口测试

    1.在线http测试:接口在线测试 模块接口测试和web接口测试: 模块接口测试是单元测试的基础。它主要测试模块的...

  • 【第八章】Jmeter接口测试实战

    本章大纲 什么是接口测试 为什么掌握接口测试 怎么做接口测试 什么是接口测试 常见web接口方式 为什么掌握接口测...

  • 接口测试 | 接口测试入门

    接口测试讲义 1. 接口测试的类型 主要包含三种测试: Web接口测试, 应用程序接口(API, applicat...

  • 接口测试的工作原理以及常见问题总结

    接口测试到底是什么?Web与移动App所提到的接口测试一样么? web开发中,接口的意思 两个不同的web工程,A...

  • 接口测试入门

    1 接口测试的类型 主要包含三种测试: Web接口测试, 应用程序接口(API, application prog...

  • 浅谈接口测试

    什么是接口测试 百度百科上面是这么说的:接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统...

  • Web与App在测试上的区别

    Web与App系统测试范围 App与Web系统测试策略 App与Web系统测试工具 在测试工具链里,接口的测试工具...

  • Web API的概念 HTTP协议基础

    刚接触接口测试的同学会很困惑,不是叫接口测试吗怎么又叫Web API呢,很多人对Web接口测试这一方面概念非常的模...

网友评论

      本文标题:web接口测试微百科

      本文链接:https://www.haomeiwen.com/subject/njlopqtx.html