尝试使用 gRPC Web 将 Envoy 连接到 gRPC 服务时出现“协议错误”
`Protocol Error` when trying to connect Envoy to gRPC service using gRPC Web
我有一个网络应用程序使用 gRPC Web 通过 dockerized Envoy 代理与我的 gRPC 服务交互。当我尝试调用 Envoy 中公开的端点时,我收到以下错误:
gRPC Error (code: 14, codeName: UNAVAILABLE, message: upstream connect error or disconnect/reset before headers. reset reason: protocol error, details: [], rawResponse: null, trailers: {content-length: 0})
这是我的客户端代码:
class FiltersService {
static ResponseFuture<Filters> getFilters() {
GrpcWebClientChannel channel =
GrpcWebClientChannel.xhr(Uri.parse('http://localhost:9000'));
FiltersServiceClient clientStub = FiltersServiceClient(
channel,
);
return clientStub.getFilters(Void());
}
}
这是我的 Envoy.yaml:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 9000 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_http1_bridge
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
upstream_connection_options:
tcp_keepalive:
keepalive_time: 300
lb_policy: round_robin
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 9001
其中 9001
端口是我的 gRPC 服务 运行ning 所在的位置。我能够通过直接从 Kreya 调用它来验证该服务是否正常工作,并且我收到了正确的响应。
我也能够从 localhost:9901
成功访问管理服务器。
但是,当我尝试通过 Kreya 或客户端调用 Envoy (9000
) 公开的端点时,我得到
gRPC Error (code: 14, codeName: UNAVAILABLE, message: upstream connect error or disconnect/reset before headers. reset reason: protocol error, details: [], rawResponse: null, trailers: {content-length: 0})
我正在 运行 将以下命令发送给 运行 Dockerized Envoy:
docker build -t my-envoy:1.0 .
docker run -p 9000:9000 -p 9901:9901 my-envoy:1.0
经过一番折腾和折腾,我终于弄明白了。查看文档,似乎 envoy.filters.httl.grpc_web
过滤器可以将请求转换为 HTTP/2 和 HTTP/3。我假设(如果在该领域有更多知识的人可以纠正我,请纠正)如果没有指定,Envoy 不知道要转换成什么协议。因此,只需将 http2_protocol_options: {}
添加到我的 cluster
即可解决问题。我在下面包含了完整的 cluster
块,以供将来可能遇到相同问题的任何人使用。
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
lb_policy: round_robin
http2_protocol_options: {}
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 9001
出于某种原因,每当我尝试在 docker run
命令中使用 --networks=host
标志时,我都无法访问管理门户,所以我遇到的解决方案和教程使用 Envoy 代理 gRPC Web 对解决这个问题不是很有帮助。希望这对面临同样问题的人有所帮助。
我有一个网络应用程序使用 gRPC Web 通过 dockerized Envoy 代理与我的 gRPC 服务交互。当我尝试调用 Envoy 中公开的端点时,我收到以下错误:
gRPC Error (code: 14, codeName: UNAVAILABLE, message: upstream connect error or disconnect/reset before headers. reset reason: protocol error, details: [], rawResponse: null, trailers: {content-length: 0})
这是我的客户端代码:
class FiltersService {
static ResponseFuture<Filters> getFilters() {
GrpcWebClientChannel channel =
GrpcWebClientChannel.xhr(Uri.parse('http://localhost:9000'));
FiltersServiceClient clientStub = FiltersServiceClient(
channel,
);
return clientStub.getFilters(Void());
}
}
这是我的 Envoy.yaml:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 9000 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.filters.http.grpc_http1_bridge
- name: envoy.filters.http.grpc_web
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
upstream_connection_options:
tcp_keepalive:
keepalive_time: 300
lb_policy: round_robin
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 9001
其中 9001
端口是我的 gRPC 服务 运行ning 所在的位置。我能够通过直接从 Kreya 调用它来验证该服务是否正常工作,并且我收到了正确的响应。
我也能够从 localhost:9901
成功访问管理服务器。
但是,当我尝试通过 Kreya 或客户端调用 Envoy (9000
) 公开的端点时,我得到
gRPC Error (code: 14, codeName: UNAVAILABLE, message: upstream connect error or disconnect/reset before headers. reset reason: protocol error, details: [], rawResponse: null, trailers: {content-length: 0})
我正在 运行 将以下命令发送给 运行 Dockerized Envoy:
docker build -t my-envoy:1.0 .
docker run -p 9000:9000 -p 9901:9901 my-envoy:1.0
经过一番折腾和折腾,我终于弄明白了。查看文档,似乎 envoy.filters.httl.grpc_web
过滤器可以将请求转换为 HTTP/2 和 HTTP/3。我假设(如果在该领域有更多知识的人可以纠正我,请纠正)如果没有指定,Envoy 不知道要转换成什么协议。因此,只需将 http2_protocol_options: {}
添加到我的 cluster
即可解决问题。我在下面包含了完整的 cluster
块,以供将来可能遇到相同问题的任何人使用。
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
lb_policy: round_robin
http2_protocol_options: {}
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: host.docker.internal
port_value: 9001
出于某种原因,每当我尝试在 docker run
命令中使用 --networks=host
标志时,我都无法访问管理门户,所以我遇到的解决方案和教程使用 Envoy 代理 gRPC Web 对解决这个问题不是很有帮助。希望这对面临同样问题的人有所帮助。