创建多个(15+)HTTP 响应过滤器,继承与组合与注入

2023-11-30

首先是关于我想要实现的目标的一些背景故事。

我正在创建一个自定义 HTTP 模块,其目的是拦截发送到多个 (15+) 不同 ArcGIS REST Web 服务的消息。拦截的请求和/或响应将被剥离基于当前用户的任何受限信息。

例如,返回多个层的调用可能会删除某些层。

未修改的响应:

"layers" : [
    {
      "id" : 0, 
      "name" : "Facilities", 
      "parentLayerId" : -1, 
      "defaultVisibility" : true, 
      "subLayerIds" : [1, 2, 3]
    }, 
    {
      "id" : 1, 
      "name" : "Hazardous Sites", 
      "parentLayerId" : 0, 
      "defaultVisibility" : true, 
      "subLayerIds" : null
    }, 
]

修改后的响应:

"layers" : [
    {
      "id" : 0, 
      "name" : "Facilities", 
      "parentLayerId" : -1, 
      "defaultVisibility" : true, 
      "subLayerIds" : [1, 2, 3]
    }
]

有许多可用的服务,所有服务都通过 URL 进行唯一标识。每个服务返回的信息非常不同,因此需要进行不同的过滤。此外,每个服务可能会以各种格式(HTML、JSON 等)返回数据。

因此,我需要创建大量不同的过滤器来应用于 HttpRequest.Filters 和/或 HttpResponse.Filters。

Example:

// Request for layers and the format is JSON
IPolicy policy = GetPolicy(userContext);
Filter filter = new LayerJsonResponseFilter(Response.Filter, policy);
Response.Filter = filter;

请求和响应过滤器是通过继承 Stream(或继承自 Stream 的其他类,例如 MemoryStream)来实现的。我希望能够轻松创建新的过滤器,而无需为每个过滤器重新实现 Stream。

这里描述了一个潜在的解决方案:http://www.west-wind.com/weblog/posts/72596.aspx

但是,我想简化解决方案,同时又不失去指定许多不同转换的灵活性,而无需重新实现流。我认为我可以通过以下方式实现这一目标:

  1. 继承自MemoryStream,以减少方法的重新实现。
  2. 始终对完整内容进行操作,而不是分块内容。
  3. 用抽象方法替换事件(例如 Filter())

我考虑了两种可能的解决方案。

解决方案1:创建多个继承自ResponseFilter的过滤器

在这种情况下,每个过滤器都包含执行过滤的逻辑。将创建超过 15 个过滤器,所有过滤器都继承自公共 ResponseFilter 抽象基类,如下所示:

// All filters will inherit from ResponseFilter
public abstract class ResponseFilter : MemoryStream
{
    public ResponseFilter(Stream stream, Policy policy) { }

    // Must be overridden in a derived class with specific Filter logic.
    public abstract string Filter(string content);

    // Overridden to cache content.    
    public override void Write(byte[] buffer, int offset, int count) { }

    // Overridden to perform the filter/transformation before the content is written.
    public override void Flush()
    {
         // Get stream content as a string

         string content = Filter(content);

         // Write new content to stream
    }
}

这将按以下方式使用。

// Example
var policy = GetPolicy();
var filter = new MapServiceJsonResponseFilter(response.Filter, policy);
response.Filter = filter;

此选项的优点是可以将类的数量保持在最低限度。然而,如果有必要的话,在应用程序中的其他任何地方重用任何过滤器逻辑就会变得困难。此外,对过滤器进行单元测试需要模拟 Stream,这是另一个缺点。

解决方案2:创建多个过滤器,注入到通用的ResponseFilter中

在这种情况下,将创建单个响应过滤器。实际的过滤器逻辑或算法被注入到过滤器中。所有过滤器都继承自抽象基类FilterBase。

// Represents an HttpResponse Filter. Renamed to avoid confusion with
// the filter algorithm.
public class ResponseFilterStream : MemoryStream
{
    public ResponseFilterStream(Stream stream, FilterBase filter) { }

    // Overridden to cache content.    
    public override void Write(byte[] buffer, int offset, int count) { }

    // Overridden to perform the filter/transformation before the content is written.
    public override void Flush()
    {
         // Get stream content as a string

         string content = _filter.Filter(content);

         // Write new content to stream
    }
}

// All filter algorithms inherit from FilterBase and must implement 
// the filter method.
public abstract class FilterBase
{
    protected TransformBase(Policy policy) { }

    // Overridden to perform the filter/transformation.    
    public abstract string Filter(string content);
}

这将按以下方式使用。

// Example
var policy = GetPolicy();
var filter = new MapServiceJsonResponseFilter(policy);
ResponseFilter responseFilter = new ResponseFilter(response.Filter, filter);
response.Filter = filter;

该解决方案的优点是过滤逻辑完全独立于任何实现流的类。如有必要,可以更轻松地重用逻辑。单元测试稍微简单一些,而且我不需要模拟流。

然而,有更多的类(恰好是 1 个),并且用法也稍微复杂一些,但也不是很复杂。

注意:我可能想重命名 FilterBase 以避免与 ResponseFilter 混淆。也许是 TransformBase。


我有几个目标希望通过任一解决方案来实现。

  1. 该解决方案必须具有高度可测试性。单元测试将用于检查过滤器的正确性。测试必须尽可能简单。
  2. 该解决方案必须轻松支持创建多个过滤器(15+)。
  3. 该解决方案应该是可读的(即易于维护)。

我认为解决方案 2 是针对该给定场景的最佳解决方案。我可以完全独立于 Stream 来测试过滤逻辑,并以最小的额外复杂性进行测试。任一解决方案都支持 #2 和 #3,因此测试具有优势。

可能还有哪些其他考虑因素?有更好的选择吗?


方案2显然是更可取的。然而,问题的主要症结似乎在于过滤器本身的构造。希望 Filter 实现中有很多可重用的组合。可以用复合部件“配置”新的过滤器吗?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建多个(15+)HTTP 响应过滤器,继承与组合与注入 的相关文章

随机推荐

  • Python 迭代器没有ext() 吗?

    Python 迭代器有吗hasnext method 捕捉的替代方案StopIteration是使用next iterator default value 例如 gt gt gt a iter hi gt gt gt print next
  • Android:如何写入SQL数据库

    我一直在尝试遵循 newBoston 教程 但当我单击按钮将数据写入数据库时 发现出现运行时错误 LogCat 显示 在活动中找不到方法 addModuleButton View 有什么建议么 添加模块活动 public class Add
  • 从另一个线程填充列表视图

    我试图从另一个类填充列表视图 但出现此错误 跨线程操作无效 控制 listView1 是从创建它的线程以外的线程访问的 在我的课堂上 我像这样声明我的列表视图 class CheckBlankPages public String pdfF
  • 使用#pragma warning push/pop 是暂时改变警告级别的正确方法吗?

    有时很难编写完全不发出警告的 C 代码 然而 启用警告是一个好主意 因此 通常有必要禁用某些特定构造的警告 并在所有其他代码片段中启用它们 到目前为止我已经看到了两种方法 第一个是使用 pragma warning push and pra
  • “main”函数的返回值去了哪里?

    在C语言中 一个函数always将其值返回给调用函数 而不是返回给其自身 如果返回类型不为 void Like int main 但是由于 main 函数是由操作系统调用 即不是一个函数 那么 main 函数返回值给谁呢 当使用表达式返回值
  • 在给定字符串中搜索字符集的最快算法

    这是我和我的一位朋友进行的一场辩论 制作一种验证方法来检查给定字符串是否具有不允许的字符之一的最快方法是什么 方法一 简单 char invalidChars toCharArray for int i 0 i lt myString le
  • 在 pandas 中按组填充缺失的日期

    我需要按组填写缺失的日期 这是创建数据框的代码 我只想将填充列的日期向下添加到填充列的日期更改时 并且仅直到组 名称 更改为止 data tdate 20080815 20080915 20081226 20090110 20090131
  • PHP无法通过python连接mysql

    我正在编写一个 PHP 来执行一个像这样连接到 mysql 的 python 脚本 在Python脚本中 coding utf 8 import mysql connector 并得到这个错误 回溯 最近一次调用最后一次 导入中的文件 do
  • 显示单元格的公式,但显示值而不是引用

    我正在使用公式在另一个单元格中显示单元格公式 我想显示这个公式中每个参考的值 而不是参考 Ex R 16 R19 T 15 R 16 想要它成为 3 2 4 2 我现在使用的函数来显示公式 Function GetFormula Cell
  • 聚合物select2元件

    我正在尝试包装很棒的 select2 jquery 小部件 https github com ivaynberg select2 在聚合物元素中以便于重复使用 我能够正确初始化选择 但在初始化后遇到问题 具体来说 当单击选择将其打开时 在定
  • 使用 gmaps4rails 显示多边形

    红宝石新手在这里 尝试使用 gmaps4rails gem 顺便说一句 很棒的 gem 在谷歌地图上将点列表显示为多边形 任何基于下面的代码示例的建议将不胜感激 我可以看到地图的轮廓 但看不到地图 也没有多边形 更新 此代码已更新 问题已解
  • 如何阻止 VS Code 在按 Enter 键时自动选择第一个建议?

    每当我在 flutter 代码中输入 Widget 函数并按 Enter 键时 VS Code 都会自动选择第一个参数建议 当我实际上想要在下一行输入该参数时 该参数会在同一行上输入 有没有办法在顶部添加一个空建议 以便我必须先按向下箭头才
  • 我需要 ($("#flip").click slipToggle ) 在同一页面上使用相同的

    我有一个使用 XSl 代码从 XML 读取的常见问题解答页面 问题和答案的 div 将重复与 XML 中的记录数一样多 这是 XSL 代码
  • android - 内存不足问题

    在我的应用程序中 我正在从网络下载图像 为此 我第一次从网络下载图像 这些图像存储在 SD 卡中 下次 我会检查这些图像是否在 SD 卡中 如果是 则从 SD 卡获取 否则我将从网络下载 这些图像像列表一样显示 我反复 意味着连续向上 向下
  • 设备和模拟器上的 Android LinkedIn 集成错误

    我正在尝试使用此问题答案集成 linkedIn从 Android 应用程序发布 LinkedIn 消息但这个给定的示例 LITest 无法在设备上工作 它向我显示了一些错误 如下所示 12 19 19 36 30 489 ERROR And
  • ES6 Yield:第一次调用 next() 的参数会发生什么?

    考虑这段代码 function foo a console log Mul a return a 2 function process start next 1 var result start console log Pre proces
  • 如何从包含像素的数组创建 BufferedImage?

    我从以下位置获取像素BufferedImage使用该方法getRGB 像素存储在名为的数组中data 对数据数组进行一些操作后 我需要创建一个BufferedImage再次这样我就可以将它传递给一个模块 该模块将显示来自该数据数组的修改后的
  • 将向量传递给函数 C++

    我有一个 main cpp test h 和 test cpp gt 我试图传递我的向量 以便我可以在 test cpp 中使用它 但我不断收到错误 file main cpp int main vector
  • Mod 将规则重写为 Zeus 服务器规则 (Codeigniter)

    我即将上线由 Codeigniter 提供支持的网站 我想从网址中删除index php 而不是这样 http www mysite com index php controller 我得到这样的东西 http www mysite com
  • 创建多个(15+)HTTP 响应过滤器,继承与组合与注入

    首先是关于我想要实现的目标的一些背景故事 我正在创建一个自定义 HTTP 模块 其目的是拦截发送到多个 15 不同 ArcGIS REST Web 服务的消息 拦截的请求和 或响应将被剥离基于当前用户的任何受限信息 例如 返回多个层的调用可