envoy filter 开发实践系列 2:官网 http filter 示例编译测试
1.前言
这篇文章开始来介绍官网中 http filter
的编译和测试过程,让大家能够知道怎么测试跑通这个例子,虽然官网已经给了代码,但是对于新手来说,这个例子虽然可以按照 readme
可以编译通过,但是测试还是有问题的,因为 envoy
的启动配置文件也是比较复杂的,要自己写一个完整能够跑通的配置文件也不容易。
所以在我这篇文章中,我会补充一个 envoy
的配置文件,一个用于可以测试这个 filter
的 http server
。昨天也把这个这些代码提交了一个 pr
,今天我有补充了一些测试启动脚本和 verify
脚本。
好接下来我们继续看怎么测试。
2.编译环境介绍
环境这里还是继续上次的,但是这里因为 http server
是 python3
写的,所以环境这里要准备一下 python3
的支持。
3.编译 http filter
在 BUILD
文件中 envoy
中的 deps
字段中加入 "//http-filter-example:http_filter_config",
,再从新编译即可。这个编译是把 echo
和 http
这两个 filter 都编译进一个 envoy
中了。
ubuntu@ubuntu:/data/mesh/envoy-filter-example$ vim BUILD
添加后的内容如下:
envoy_cc_binary(
name = "envoy",
repository = "@envoy",
deps = [
":echo2_config",
"//http-filter-example:http_filter_config",
"@envoy//source/exe:envoy_main_entry_lib",
],
)
也可以直接使用下面的命令,单独编译 http-filter。
bazel build //http-filter-example:envoy
4.测试流程
4.1 流程介绍
整体的测试流程如下:
- 启动一个 web 服务器
- 编写 envoy 启动配置文件
- 使用配置文件启动 envoy
- 使用命令行 curl 测试
测试示意
官网这个 http filter 功能非常简单,其目的就是在 http 请求头中加入一个 kv 健值对,并且是把 key 转换为小写字母。
const LowerCaseString HttpSampleDecoderFilter::headerKey() const {
return LowerCaseString(config_->key()); // 这里转大写为小写
}
const std::string HttpSampleDecoderFilter::headerValue() const {
return config_->val(); // 获取配置中的val值
}
FilterHeadersStatus HttpSampleDecoderFilter::decodeHeaders(RequestHeaderMap& headers, bool) {
// add a header
headers.addCopy(headerKey(), headerValue()); // 添加到 http 的请求头中
return FilterHeadersStatus::Continue;
}
4.2 web 服务
为了简单就直接使用 python 起一个 web server 来测试,在 web server 中打印接收到的 http header。下面是根据网上的例子修改而来的一个简单的 web 服务程序。
这个测试程序中有个一非常特别的地方,可以看到在 do_GET
方法中除了给客户端返回一个字符串 Hello World !rn
外,还要把自己接收到的 http header
返回给客户端。
#!/usr/bin/python3
from http.server import BaseHTTPRequestHandler,HTTPServer
HTTP_PORT = 8081
# This class will handles any incoming request
class doHandler(BaseHTTPRequestHandler):
# Handler for the GET requests
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
print(self.headers)
# Send the message
self.wfile.write(b"Hello World !rn")
self.wfile.write(self.headers.as_bytes()) # 把接收到的 http header 返回给客户端。
return
try:
# Create a http server and define the handler to manage the request
server = HTTPServer(('', HTTP_PORT), doHandler)
print('Started httpserver on port ' , HTTP_PORT)
# Wait forever for incoming http requests
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down the web server')
server.socket.close()
~
4.3 测试配置文件
配置文件继承上面一个配置文件,所以大家可以看到大部分内容都是一样。修改内容有 2 点:
- 在后端服务端口这里修改为了
8081
。 - filter 配置增加 http filter 的管理。
- 添加 http_filters,我们测试的 http_filters 名字是 sample。
config.yaml
admin:
access_log_path: /dev/null
address:
socket_address:
address: 127.0.0.1
port_value: 0
static_resources:
clusters:
name: cluster_0
connect_timeout: 0.25s
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
listeners:
- name: listener_0
address:
socket_address:
address: 127.0.0.1
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
codec_type: auto
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: cluster_0
http_filters:
- name: sample # before envoy.router because order matters!
typed_config:
"@type": type.googleapis.com/sample.Decoder
key: Via
val: sample-filter
- name: envoy.router
typed_config: {}
启动 web & envoy 服务
下面这个脚本就是启动 http 服务和使用上面的配置文件启动 envoy
。
#!/bin/sh
python3 ./http-filter-example/httpserver.py&
./bazel-bin/envoy --config-path ./http-filter-example/config.yaml
测试
测试过程比较简单,在 http 服务中已经把它接收到的 header 发反给客户端,所以可以直接在客户端中看到传递到 http 服务的请求 header。下面的测试中可以看到 header
中有 via: sample-filter
,而且 via
都是小写的(我们在配置中是配置的是 Via
)。
$ curl http://127.0.0.1:8080
Hello World !
host: 127.0.0.1:8080
user-agent: curl/7.58.0
accept: */*
x-forwarded-proto: http
x-request-id: 3ee226cc-4e88-4ead-84e7-511406b95748
via: sample-filter
x-envoy-expected-rq-timeout-ms: 15000
content-length: 0
总结
http filter
的这个例子比 echo
的例子要复杂一点,配置文件也复杂,还需要额外的写测试服务程序。但是这个例子是一个非常完整的例子。让我们完整的从客户端到 envoy
,到后端服务,整个流程都已经走过了。我认为走过了这个例子,大家都知道了 filter
的开发测试流程,尤其目前 http
仍然作为主要的通信协议,在 web 时代中还处于主导位置。而且实际上我们在企业使用开发的 http filter
是最多的,目前我们在内部积累了超过 40 个各种场景下的 http filter
。所以我认为学会了这个,大家的 http filter
开发就算是入门了。
- 【Python量化投资】基于网格优化、遗传算法对CTA策略进行参数优化
- 将我的 Windows Phone 应用程序更新到 Windows Phone 8
- 绑定子类的泛型基类,反模式?
- 给创业码农的话--如何提升开发效率
- 基于OEA框架的客户化设计(二) 元数据设计
- 自定义actionbar
- (转)JS算法系列-数组去重
- 基于OEA框架的客户化设计(三) “插件式”DLL
- 居中“魔法”总结
- Windows微信DPI适配
- 采用Symbol和process.nextTick实现Promise
- MongoDB 如何使定制电子商务变得简单
- 代码重构之路的艰辛
- 量化投资之机器学习应用——基于 SVM 模型的商品期货择时交易策略(提出质疑和讨论)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Geant4--G4ParticleGun定义射线源的发射能谱
- Sony-PMCA-RE, 反向工程索尼PlayMemories相机应用
- 中标麒麟系统Your trial is EXPIRED and no VALID licens
- R初探
- 独家 | 在Python编程面试前需要学会的10个算法(附代码)
- 为什么一个还没毕业的大学生能够把 IO 讲的这么好?
- 如何将单 master 升级为多 master 集群
- 为 Kubernetes 节点发布扩展资源
- Kubernetes 资源预留配置
- PHP一些常见的漏洞梳理
- File的基本操作
- 一文教你在Colab上使用TPU训练模型
- 如何在Docker容器中运行Docker [3种方法]
- [漏洞复现] 三.CVE-2020-0601微软证书漏洞及Windows验证机制欺骗复现
- PDF文件密码破解