惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AI
AI
L
LINUX DO - 最新话题
The Register - Security
The Register - Security
T
Threatpost
Y
Y Combinator Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Attack and Defense Labs
Attack and Defense Labs
T
Tailwind CSS Blog
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
H
Heimdal Security Blog
小众软件
小众软件
D
Docker
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
The Exploit Database - CXSecurity.com
AWS News Blog
AWS News Blog
腾讯CDC
博客园 - 司徒正美
美团技术团队
L
LINUX DO - 热门话题
N
Netflix TechBlog - Medium
Stack Overflow Blog
Stack Overflow Blog
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
爱范儿
爱范儿
N
News and Events Feed by Topic
J
Java Code Geeks
F
Fortinet All Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
U
Unit 42
V2EX - 技术
V2EX - 技术
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tor Project blog
H
Help Net Security
The GitHub Blog
The GitHub Blog
L
Lohrmann on Cybersecurity
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
PCI Perspectives
PCI Perspectives
W
WeLiveSecurity
A
About on SuperTechFans
N
News and Events Feed by Topic
博客园 - 叶小钗
Cloudbric
Cloudbric
L
LangChain Blog
WordPress大学
WordPress大学
B
Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed

HTTP

用上了 Let’s Encrypt 的 IP 证书,太香了 - V2EX safari 无法打开网站,但 chrome 可以 - V2EX 大家一般如何保证服务器 set-cookie 按序保存的 - V2EX 明御 WEB 应用防火墙 如何找回密码? - V2EX 直连模式下 https 网站打不开 - V2EX 关于在其他国家访问中国国内数据出现严重丢包问题 - V2EX 求教同样的 url 参数头部 cookies, scrapy 请求返回验证码, requests 直接请求就正常,代码如下 - V2EX 什么工具适合方便的发送原始 HTTP 包? - V2EX 冷知识:.ml 域名可以注册了 - V2EX TLS 回顾 - V2EX 想监测某航空余票 - V2EX http 代理,如果不支持 connect 方法,有没有办法访问 https 的网站? - V2EX 关于 tomcat 配置国密 https 后出现的问题求助 - V2EX 一个 udp 的疑问 - V2EX tradingview 上面策略的买入 卖出信号怎样发送给服务器,现在 webhook URL 现在收费 有什么办法可以解决的 - V2EX 选择重传协议疑问 - V2EX 有个用于测试 HTTPS 链接各阶段耗时的命令行工具想不起来叫啥了 - V2EX 求各位高手推荐一个 postman 的 mac 下的替代。。 - V2EX 有现成的 Http 请求批量发送和管理工具吗? - V2EX 报文主体和实体主体的差异 - V2EX 请教一下各位, http2 的头部有什么简单的方法去解码吗? - V2EX 后 911S5 时代 各路 ip 代理的对比与选择 (仅供参考) - V2EX HTTP 协议 HEAD 请求,会有查询字符串吗? - V2EX 一个 http 请求由多个 tcp 数据包组成,一个 tcp 连接可以发送多个 http 请求,是这样吗? - V2EX httpCanary 的上传服务器插件,这个应该如何配置? - V2EX 请教各位技术大大一个 websocket 消息丢失的问题 - V2EX 某些网站在特定的提交中需要手工选择 chrome 的证书,这是 https 的双向认证吗 - V2EX HTTP/2 长连接的存续期多久? - V2EX REST 祖师爷 Roy Fielding 说: RPC 就不适合 RESTful 风格。只有超文档适合用 REST - V2EX 2022 年 TLS 1.3 HTTP/2 下到底该不该开启 Gzip 压缩? - V2EX 可以不关闭服务替换证书吗? 谢谢 - V2EX 关于 HTTP 中编码一点疑问 - V2EX http 代理 vs. https 代理 - V2EX 付费求解 curl ssl/tls 突发状况,请求 https 站点均失败。 - V2EX HTTP 标准中将会增加的两个新的和缓存有关的 Response header - V2EX 请教大佬有关 http/3 支持的问题 - V2EX 如何分辨网站是伪静态还纯静态网址? - V2EX 关于 querystring 疑问 - V2EX 接口(服务端)如何判断客户端是否已经关闭此次 http 请求了 - V2EX 居然 http 还有 418 这么个状态码 - V2EX 切换到 http2 对开发人员是有感知的吗? - V2EX 关于 quic 第一次连接 需要 tcp(http2)支持的困惑 - V2EX Postman 200 然而 curl 302 - V2EX 怎么用 httpcanary 在安卓 7 抓小程序的包? - V2EX 如何安全地将局域网内的 http 服务暴露在公网? - V2EX 关于 HTTP 代理的疑惑 - V2EX 对 HTTP3 的性能疑惑 - V2EX 关于 https 双向认证的细节 - V2EX
关于 http 处理 grpc-gateway stream 流式响应时的问题 - V2EX
HUNYXV · 2021-05-11 · via HTTP

http 请求 stream 响应时,response body 打印出来是正确的结果:

		{"result":{"code":1,"msg":"1111"}}
        {"result":{"code":2,"msg":"2222"}}
        {"result":{"code":3,"msg":"3333"}}
        {"result":{"code":4,"msg":"4444"}}
        {"result":{"code":5,"msg":"5555"}}
        {"result":{"code":6,"msg":"6666"}}

但是使用runtime.JSONPb.Decode 时,也会得到五个结果,但每个 decode 出来是个 nil... :

=== RUN   TestHttpRespStream
    service_test.go:147: resp: <nil>
    service_test.go:147: resp: <nil>
    service_test.go:147: resp: <nil>
    service_test.go:147: resp: <nil>
    service_test.go:147: resp: <nil>
    service_test.go:147: resp: <nil>
    service_test.go:149: EOF
--- PASS: TestHttpRespStream (0.62s)

这是 proto 文件:

// ./pb/test.proto

syntax = "proto3";

package pb;

option go_package = "/pb;pb";

import "google/api/annotations.proto";

message Req {
    int32 id = 1;
    string name = 2;
}

message Resp {
    int32 code = 1;
    string msg = 2;
}

service TestService {
    rpc QueryStreamResp(Req) returns (stream Resp){
        option (google.api.http) = {
            post: "/query-stream-resp"
            body: "*"
        };
    };
    rpc QueryStreamReq(stream Req) returns (Resp){
        option (google.api.http) = {
            post: "/query-stream-req"
            body: "*"
        };
    };
    
    rpc Query(stream Req) returns (stream Resp){
        option (google.api.http) = {
            post: "/query"
            body: "*"
        };
    };
}

grpc 服务端:

func (ts *TestService) QueryStreamResp(req *pb.Req, stream pb.TestService_QueryStreamRespServer) error {
	log.Printf("QueryStreamResp|start...|req: %+v\n", req)
	result := []*pb.Resp{
		{Code: 1, Msg: "1111"},
		{Code: 2, Msg: "2222"},
		{Code: 3, Msg: "3333"},
		{Code: 4, Msg: "4444"},
		{Code: 5, Msg: "5555"},
		{Code: 6, Msg: "6666"},
	}

	// header := make(metadata.MD)
	// header.Append("content-type", "application/json")
	// stream.SendHeader(header)
	for i := range result {
		log.Printf("resp: %+v", result[i])
		
		if err := stream.Send(result[i]); err != nil {
			log.Fatal(err)
		}
		time.Sleep(100 * time.Millisecond)
	}
	log.Println("QueryStreamResp|stop...")

	return nil
}

单元测试:

func TestHttpRespStream(t *testing.T) {
	url := "http://127.0.0.1:8080/query-stream-resp"
	reqData := &pb.Req{Id: 1, Name: "111"}

	var buffer bytes.Buffer
	encoder := (&runtime.JSONPb{}).NewEncoder(&buffer)

	if err := encoder.Encode(reqData); err != nil {
		t.Fatal(err)
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, &buffer)
	if err != nil {
		t.Fatal(err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	// body, err := ioutil.ReadAll(resp.Body)
	// if err != nil {
	// 	t.Fatal(err)
	// }
	// t.Logf("body: %s", string(body))
	jsonb := new(runtime.JSONPb)
	dencoder := jsonb.NewDecoder(resp.Body)

	for {
		var result *pb.Resp
		err := dencoder.Decode(result)
		if err == nil {
			t.Logf("resp: %+v", result)
		} else {
			t.Logf("%+v", err)
			break
		}
	}
}