当前位置: 首页 > 科技观察

基于HTTP请求拦截,快速解决跨域和代理Mock

时间:2023-03-14 16:14:50 科技观察

近年来,随着Web开发的逐渐成熟,前后端分离的架构设计越来越被众多开发者认可,让前后端专注于自己的功能,减少沟通成本,提高开发效率。在前后端分离的开发模式下,前后端工程师可以并行工作。当前端界面展示了需要的数据,而后端相应的界面还没有开发出来时,就需要一个数据源来保证前端工作的顺利进行。在今天的文章中,我们将介绍几种常用的方法以及其中存在的问题,并提出如何快速解决基于HTTP请求拦截的跨域和代理mock问题。常见方法及问题请求mock服务器最常见的方式是维护一个提供静态数据的mock服务器(它提供的数据称为mock数据),前端可以请求mock服务器获取数据,但是这种静态数据不方便维护。更好的请求AMP的方式是有一个mockserver根据接口定义自动生成数据,我们称之为AMP(InterfaceManagementPlatform,APIManagePlatform),前端向server请求获取数据。这种场景下,如果已经开发了一些接口,前端需要手动修改代码,设置不同接口的请求地址。当接口数量很大时,这种方法变得非常低效。所以AMP一般同时也会提供一个代理功能,即前端仍然请求AMP,AMP会根据接口的完成情况决定返回mock数据,还是将请求代理到真正的业务服务器去获取数据并返回。但是这个方案的问题是,当涉及到需要角色权限验证的接口时,登录输入用户信息后,浏览器会缓存cookies。当访问与登录时同域名的界面时,浏览器会自动携带cookies。服务器解析cookie,认证后获取相应权限的接口数据。前端一般在本地启动服务器进行开发。当开发业务服务器的接口,然后使用请求AMP的方式切换接口数据时,就会出现跨域的情况。由于浏览器的安全机制决定了跨域访问时不能携带cookie,无法通过代码读取cookie,所以通过代码跨域传递cookie是不可行的,现有的解决方案都不是***:如果附加AMP增加了模拟登录的功能,会返回相应的数据,因为所有接口的权限都是固定的,不可能适配一个接口对不同的角色有不同的权限;而一旦认证接口功能发生变化或失效,就需要重写修改AMP的代理功能,代价高昂。如果使用浏览器插件保存登录信息并提供代理,需要兼容不同的浏览器,成本太高。针对以上技术问题,本文提出了一种无需侵入业务代码即可在前端实现的跨浏览器代理方法。基于HTTP请求拦截实现前端接口代理基于HTTP请求拦截实现前端接口的方法实现了接口开发完成前后的mock数据与业务服务器真实数据的切换一个更底层的视角,解决了现有技术中存在的问题。HTTP请求通过AMP代理到业务服务器,导致无法跨域携带权限信息的技术问题,导致无法根据角色权限返回请求的数据。主要创新是在底层实现了基于XMLHttpRequest和FetchAPI的拦截代理,没有考虑主流浏览器类型和JavaScript依赖的工具库;在前端实现代理,保留登录信息,不需要额外处理认证问题;提供一种可以快速实现和可插拔的用法。总的来说,该方案提供了一种请求代理方式,可以快速实现,运行在前端浏览器中,不依赖于浏览器类型。设计思路Web前端开发一般使用JavaScript语言。浏览器环境下的HTTP请求是基于FetchAPI或XMLHttpRequestAPI实现的(基于前者的请求记录为xhr,基于后者的请求记录为fetch)。主流的Javascript开源工具库如Axios和Request也是如此。所以我们的方案是通过在底层拦截xhr或者fetch,根据一定的判断逻辑实现前端代理功能。实现方式首先,在浏览器环境中重新封装原生的XMLHttpRequestAPI和FetchAPI。基本思路是将这两个原生API保存下来,分别添加到各自重新封装的同名API中(记为新API),为新API编写与原生API同名的方法和属性,以及添加请求参数同名方法(比如下面的open和send)添加拦截请求和代理逻辑ApiProxy,并开启一个可以配置拦截逻辑的接口,用于配置请求数据的拦截和代理逻辑不同的HTTP请求格式。图1:Proxy、AMP与终端业务的交互流程。ApiProxy在这个过程中的主要作用和工作流程可以概括为:注册拦截器。接收并拦截HTTP请求,解析请求中的参数。这里的参数是指在AMP中可以唯一标识接口的参数,如域名+请求方式(如GET、POST等)+路径(如.com/user中的https://service/user).根据此参数生成发送AMP的请求。AMP实时维护mock服务器上存储的接口和业务服务器上存储的真实接口的相关信息,包括接口定义、域名、属性、开发状态等,AMP根据请求查询接口定义数据。如果接口存在,状态为开发中,则返回根据接口定义生成的mock数据,否则返回具体的响应标志,如图1中“{code:』200302}”所示。接收后AMP的响应,Apiproxy判断是否有特殊标志。如果不直接向原始请求返回mock数据,则说明后端接口开发完成,继续向后端服务器发送原始HTTP请求,请求存储在真实数据中的真实数据后端服务器。所以没有对原始请求进行任何处理。不同于传统的向AMP发送HTTP请求的方式,AMP根据接口状态判断是直接根据请求返回mock数据,还是让proxy向业务服务器发送HTTP请求(此时,跨域访问会丢失原HTTP请求中的浏览数据(服务器携带的cookie),而不是直接将HTTP请求发送给AMP,而是在请求正式发送前进行拦截,解析参数后发送到AMP,AMP会反馈接口的状态,如果开发完成,就会正式发送HTTP请求给业务服务器。由于请求没有修改,只是延迟了发送,所以原请求与业务服务器之间的认证等所有相关信息都保持不变,从而解决了跨域访问不能携带cookies的问题。由于不同请求方式的底层设计不同,ApiProxy在不同请求方式下的实现是不同的,我们对应的具体封装方式也不同。图2:Proxy核心工作原理XMLHttpRequest对于XMLHttpRequest请求,在其open方法中解析请求,访问AMP根据响应结果判断是否继续向后台服务器发送原请求,一个xhr只有在发送时才是真实的方法被调用发起了HTTP请求,但是在open方法中获取不到send方法传过来的数据,所以拦截发生在send方法中。先将发送请求时的参数单独存放在send方法中,然后直接返回,保证不会先调用真正的XMLHttpRequest的send方法,并从单独存放的参数中生成对AMP的请求,执行中的判断上面的AMP。示例1.定义一个与原生XMLHttpRequestAPI同名的接口,称为新的XHR接口;2.重命名原生的XMLHttpRequestAPI,添加到新的XHR接口中;3、在新的XHR接口和方法中定义一个与原生XMLHttpRequestAPI同名的属性;4、解析open方法中的同名HTTP请求,获取AMP中用于查询接口状态的参数(如域名+请求方法+路径);5.拦截原请求发送,在同名的send方法中暂存原请求发送的数据,暂停原请求的发送;6、使用4中的参数请求AMP,查询接口状态,如果接口不存在或者已经完成,则返回一个特殊标志,ApiProxy取出5中的暂存,将数据传给原请求,继续发送原始请求;否则,AMP返回模拟数据,ApiProxy直接将数据返回给原始请求。FetchAPI对于FetchAPI,由于是基于Promise,拦截相对容易。你只需要在FetchAPI的外层封装一个Promise入口即可。在它发起fetch请求之前,先暂停原请求,解析数据请求AMP,并等待响应,判断响应是否有特殊的响应码,如果有则继续原请求,否则跳过原请求,以及直接返回模拟数据。启动前端代理功能在实际的前端开发中,可以使用打包工具,如webpack,自定义一个可配置的插件。打开后会自动在开发环境的主页面插入代理拦截代码,启动前端代理功能。总结本文提出的前端代理方式,通过将代理责任下沉到前端,减少了模拟服务器(或接口管理平台)请求真实业务服务器的步骤,同时保持角色权限在前端请求,进一步减轻了代理的负担。工作负载,从底层拦截HTTP请求的方法,绕过了使用浏览器插件作为代理带来的浏览器兼容性问题。***提供的代理方法使用打包工具(如webpack)封装该代理方法,实现快速插件化的前端代理。本文作者:邓忠哲,马蜂窝社区研发团队前端开发工程师,主要负责社区管理后台和界面管理平台开发。附件:关于跨域的参考资料:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS关于XMLHTTPRequest:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest关于Fetch:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API】点此查看作者更多好文