GRPC头记录

http://nodejs.cn/api/http2/note_on_authority_and_host.html

https://cloud.tencent.com/developer/section/1189948

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/User-Agent

Header说明

:authority

个人理解:可视为host,表示服务的IP+Port

HTTP/2 要求请求具有 :authority 伪标头或 host 标头。 当直接构建 HTTP/2 请求时首选 :authority,从 HTTP/1 转换时首选 host(例如在代理中)。

如果 :authority 不存在,则兼容性 API 将回退到 host。 有关详细信息,请参阅 request.authority。 但是,如果不使用兼容性 API(或直接使用 req.headers),则需要自己实现任何回退行为。
":authority" 伪头字段包含目标 URI 的部分权限([RFC3986],第 3.2 节)。权限不得包含 "http" 或 "https" scheme URI 的已弃用 "userinfo" 子组件。为了确保可以准确地再现 HTTP/1.1请求行,当从具有源或星号形式的请求目标的 HTTP/1.1 请求进行转换时,必须省略该伪头字段(参见[RFC7230],第 5.3 节)。直接生成 HTTP/2 请求的客户端应该使用 ":authority" 伪头字段而不是 Host 头字段。将 HTTP/2 请求转换为 HTTP/1.1 的网络中间件必须通过复制 ":authority" 伪头字段的值来创建 Host 头字段(如果请求中不存在的话)。

user-agent

User-Agent 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。

记录说明

  • 192.168.10.173 PC1-IP
  • 192.168.10.96 PC2-IP
  • 192.168.10.152 kong网关-IP
  • c++ 服务在173运行
  • golang服务在96运行
  • 标签为服务,子标签为客户端

C++ Service

c++直接访问

Client metadata:
Header key: user-agent, value: grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)

golang访问

Client metadata:
Header key: user-agent, value: grpc-go/1.46.2

kong网关-c++

Client metadata:
Header key: user-agent, value: grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)
Header key: x-forwarded-for, value: 192.168.10.173
Header key: x-forwarded-host, value: 192.168.10.152
Header key: x-forwarded-path, value: /hello.HelloService/SayHello
Header key: x-forwarded-port, value: 8508
Header key: x-forwarded-proto, value: http
Header key: x-real-ip, value: 192.168.10.173

kong网关-golang

Client metadata:
Header key: user-agent, value: grpc-go/1.46.2
Header key: x-forwarded-for, value: 192.168.10.96
Header key: x-forwarded-host, value: 192.168.10.152
Header key: x-forwarded-path, value: /hello.HelloService/SayHello
Header key: x-forwarded-port, value: 8508
Header key: x-forwarded-proto, value: http
Header key: x-real-ip, value: 192.168.10.96

kong网关-grpc_web

Client metadata:
Header key: accept, value: application/grpc-web-text
Header key: accept-encoding, value: gzip, deflate
Header key: accept-language, value: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Header key: content-length, value: 9
Header key: origin, value: http://192.168.10.173:8080
Header key: referer, value: http://192.168.10.173:8080/
Header key: user-agent, value: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
Header key: x-forwarded-for, value: 192.168.10.96
Header key: x-forwarded-host, value: 192.168.10.152
Header key: x-forwarded-path, value: /hello.HelloService/SayHello
Header key: x-forwarded-port, value: 8509
Header key: x-forwarded-prefix, value: /hello
Header key: x-forwarded-proto, value: http
Header key: x-grpc-web, value: 1
Header key: x-real-ip, value: 192.168.10.96
Header key: x-user-agent, value: grpc-web-javascript/0.1

Golang Service

c++ 直接访问

Client metadata:
:authority :: [192.168.10.96:8503]
content-type :: [application/grpc]
grpc-accept-encoding :: [identity, deflate, gzip]
user-agent :: [grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)]

golang 访问

Client metadata:
:authority :: [192.168.10.96:8503]
content-type :: [application/grpc]
user-agent :: [grpc-go/1.46.2]

kong网关- golang

Client metadata:
x-forwarded-path :: [/hello.HelloService/SayHello]
x-real-ip :: [192.168.10.96]
x-forwarded-for :: [192.168.10.96]
x-forwarded-port :: [8508]
x-forwarded-host :: [192.168.10.152]
content-type :: [application/grpc]
user-agent :: [grpc-go/1.46.2]
:authority :: [192.168.10.96:8503]
x-forwarded-proto :: [http]

kong网关- c++

Client metadata:
x-forwarded-for :: [192.168.10.173]
content-type :: [application/grpc]
grpc-accept-encoding :: [identity, deflate, gzip]
x-forwarded-port :: [8508]
x-forwarded-host :: [192.168.10.152]
x-real-ip :: [192.168.10.173]
x-forwarded-path :: [/hello.HelloService/SayHello]
user-agent :: [grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)]
:authority :: [192.168.10.96:8503]
x-forwarded-proto :: [http]

kong网关- grpc_web

Client metadata:
referer :: [http://192.168.10.173:8080/]
x-forwarded-for :: [192.168.10.96]
x-forwarded-path :: [/hello.HelloService/SayHello]
accept-language :: [zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6]
content-length :: [9]
x-forwarded-port :: [8509]
accept :: [application/grpc-web-text]
x-grpc-web :: [1]
x-real-ip :: [192.168.10.96]
x-user-agent :: [grpc-web-javascript/0.1]
accept-encoding :: [gzip, deflate]
x-forwarded-prefix :: [/hello]
user-agent :: [Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53]
content-type :: [application/grpc]
origin :: [http://192.168.10.173:8080]
x-forwarded-host :: [192.168.10.152]
:authority :: [192.168.10.96:8503]
x-forwarded-proto :: [http]

总结

获取客户端IP

C++ 服务端

  • C++直接访问
  • Go直接访问
  • C++访问kong
  • Go访问kong
  • Grpc-WEB访问网关
C++暂时未实现如何从**context**`获取客户端IP`

服务端如果有需要,建议和客户端约定一个**Key**作为`header`

Go 服务端

  • C++直接访问
  • Go直接访问
  • C++访问kong
  • Go访问kong
  • Grpc-WEB访问网关

虽然Go在直接访问时,无法从header中读取到客户端IP相关,但通过google.golang.org/grpc/peer包获取到客户端IP

p, _ := peer.FromContext(ctx)
fmt.Println(p.Addr.String()," ",p.Addr.Network()) Addr()为IP,NetWork为传输方式(tcp/udp/..)

MetaData

Go metadata

    ## clinet code
ctx := context.Background()
md := metadata.New(map[string]string{"demo": "go client"})
newCtx2 := metadata.NewOutgoingContext(ctx, md) - go service:
Client metadata:
user-agent :: [grpc-go/1.46.2]
demo :: [go client]
:authority :: [192.168.10.96:8503]
content-type :: [application/grpc] - c++ service:
Client metadata:
Header key: go, value: programming
Header key: tour, value: book
Header key: user-agent, value: grpc-go/1.46.2

C++ metadata

    ## clinet code
grpc::ClientContext context;
context.AddMetadata("demo", "c++ client"); - go:
Client metadata:
:authority :: [192.168.10.96:8503]
content-type :: [application/grpc]
grpc-accept-encoding :: [identity, deflate, gzip]
user-agent :: [grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)]
demo :: [c++ client] - c++:
Client metadata:
Header key: demo, value: c++ client
Header key: user-agent, value: grpc-c++/1.46.0-dev grpc-c/23.0.0 (linux; chttp2)

测试程序

proto

syntax = "proto2";

package hello;
option go_package = "./hello";
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse);
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
} message HelloRequest {
optional string greeting = 1;
} message HelloResponse {
required string reply = 1;
}

Go

/*
GRPC 服务端
*/
package main import (
"context"
pb "demo_hello/proto/hello"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"log"
"net"
) type Server struct {
pb.UnimplementedHelloServiceServer
} func (S *Server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
res := "this is 96"
fmt.Println("Client metadata:")
if headers, ok := metadata.FromIncomingContext(ctx); ok {
for head, val := range headers {
fmt.Println(head, " :: ", val)
}
}
return &pb.HelloResponse{Reply: &res}, nil
}
func main() {
lis, err := net.Listen("tcp", "0.0.0.0:8503")
if err != nil {
log.Fatalf("failed listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterHelloServiceServer(s, &Server{})
log.Printf("Server listen:%v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("Failed Server: %v", err)
}
}
/*
GRPC 客户端
*/
package main import (
"context"
"flag"
"google.golang.org/grpc/metadata"
"log"
"time" pb "demo_hello/proto/hello"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
) const (
defaultName = "world"
) var (
addr = flag.String("addr", "192.168.10.96:8503", "the address to connect to")
) func main() {
flag.Parse()
// Set up a connection to the server.
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewHelloServiceClient(conn) // Contact the server and print out its response.
ctx := context.Background()
md := metadata.New(map[string]string{"demo": "go client"}) newCtx2 := metadata.NewOutgoingContext(ctx, md)
ctx, cancel := context.WithTimeout(newCtx2, time.Second)
defer cancel()
name := "ss"
r, err := c.SayHello(ctx, &pb.HelloRequest{Greeting: &name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetReply())
}

C++

/*
GRPC server
*/
#include <iostream>
#include <memory>
#include <string> #include <grpcpp/grpcpp.h> #ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "hello_world/hello_world.grpc.pb.h"
#endif using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using hello::HelloRequest;
using hello::HelloResponse;
using hello::HelloService;
using Service = hello::HelloService::Service;
// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Service {
Status SayHello(ServerContext *context, const HelloRequest *request, hello::HelloResponse *reply) override {
std::string prefix("Hello "); // Get the client's initial metadata
std::cout << "Client metadata: " << std::endl;
const std::multimap<grpc::string_ref, grpc::string_ref> metadata = context->client_metadata();
for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) {
std::cout << "Header key: " << iter->first << ", value: ";
// Check for binary value
size_t isbin = iter->first.find("-bin");
if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) {
std::cout << std::hex;
for (auto c : iter->second) {
std::cout << static_cast<unsigned int>(c);
}
std::cout << std::dec;
} else {
std::cout << iter->second;
}
std::cout << std::endl;
} reply->set_reply("173");
return Status::OK;
}
}; void RunServer() {
std::string server_address("0.0.0.0:8503");
GreeterServiceImpl service; ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl; // Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
} int main(int argc, char **argv) {
RunServer(); return 0;
}
/*
GRPC client
*/
//
// Created by mimo on 2022/5/24.
//
#include "iostream" #include "memory" #include "grpcpp/grpcpp.h"
#include "hello_world/hello_world.grpc.pb.h" using namespace std;
using namespace hello;
class HelloClient {
public:
explicit HelloClient(const std::shared_ptr<grpc::Channel> &channel)
: stub_(hello::HelloService::NewStub(channel)) {} void SayHello() {
grpc::ClientContext context;
context.AddMetadata("demo", "c++ client");
HelloRequest request;
HelloResponse response; request.set_greeting("dd"); auto res = stub_->SayHello(&context, request, &response);
if (!res.ok()) {
std::cout << "Failed IsConnected alarm server" << std::endl;
return;
}
std::cout << response.reply();
} private:
std::unique_ptr<hello::HelloService::Stub> stub_;
}; int main(){
HelloClient client(grpc::CreateChannel("192.168.10.96:8503", grpc::InsecureChannelCredentials()));
client.SayHello();
return 0;
}

最新文章

  1. TYPESDK手游聚合SDK服务端设计思路与架构之三:流程优化之订单保存与通知
  2. EMLS项目推进思考
  3. CSS光标属性一览表
  4. iOS系统控件显示中文
  5. secureCRT使用VIM时对语法高亮
  6. PHP中长连接的实现
  7. (转载)Linux系统调用及用户编程接口(API)
  8. Bash判断是否是root
  9. TCP/IP-入门
  10. WEB程序会话管理--HttpSession和Cookie
  11. C++实现20个设计模式
  12. CDOJ 631 敢说敢做 记忆化搜索and动规
  13. linux 内核 zImage 生成过程分析
  14. 理解Java类加载机制(译文)
  15. uploadPreview上传图片前预览图片
  16. 关于VMware(虚拟机) 出现错误时处理办法
  17. Practical Node.js (2018版) 13章, Node HTTP/2 Servers
  18. Luogu3320 SDOI2015 寻宝游戏 链并
  19. android 短信拦截
  20. Qt中(图片)资源的使用方式

热门文章

  1. Json序列化与反序列化导致多线程运行速度和单线程运行速度一致问题
  2. Base64隐写
  3. 设计并实现大数类 BigNum
  4. 戏说领域驱动设计(廿七)——Saga设计模型
  5. node包的降版本
  6. ES6 Promise 的链式调用
  7. Win10系统下怎么让局域网内其他电脑通过IP访问网站
  8. 【ACM程序设计】动态规划 第二篇 LCS&amp;LIS问题
  9. 使用 Nocalhost 开发 Rainbond 上的微服务应用
  10. 6月6日,HTTP/3 正式发布了!