英文:
Serve REST requests over grpc Server
问题
我来帮你翻译一下:
我在这个链接上看到了这个问题:https://stackoverflow.com/questions/66931877/handle-rest-requests-in-golang-grpc-server/73026116#73026116
我试图做与链接中描述的类似的事情。但是,我不仅仅是记录信息,我还想将从HTTP请求中获取的变量传递给RPC调用。
这种做法可行吗?之所以必须使用RPC调用,是因为grpc服务器和客户端之间进行的是双向流式传输,并且数据必须返回给发出HTTP请求的用户进行处理。
func (s *Server) ConnectAndStream(input *Input, channelStream TestApiService_ConnectAndStreamServer) error {
// TO-DO: 这个id必须来自HTTP请求
var id int32 = 1234566
// id := a.ConnectAndExchange
log.Println("来自sam用户的Id:", id)
// var id int32 = 1234566
for i := 1; i <= 2; i++ {
id += 1
log.Println("Speed Server正在发送数据:", id)
channelStream.Send(&Input{Id: id})
}
for i := 1; i <= 2; i++ {
log.Println("现在是接收的时间")
client_response, err := channelStream.Recv()
log.Println("来自samd客户端的响应:", client_response.Id)
if err != nil {
log.Println("从samd接收时出错:", err)
}
}
return nil
}
内联代码注释:目前id是硬编码的,需要从HTTP请求中获取。
更新:根据建议,这是我的尝试,还修改了RPC函数以接受一个输入,这样我就能从HTTP请求中传递它。
func main() {
go runGrpc() // 这个函数监听传入的连接并为grpc服务器注册端点
log.Printf("*------ 等待来自SAM用户的请求 ------*")
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/exchangeId/{test_id}", ConnectAndExchange).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", router))
}
func (s *Server) ConnectAndExchange(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
test_id, _ := strconv.Atoi(vars["test_id"])
log.Println("来自用户的测试id请求:", test_id)
// 猜测:需要将这部分代码放在一个go协程中,因为当输入test_id时,预期会有一系列的响应流
res := s.ConnectAndStream(test_id)
// 处理响应给用户
// w.Write(res)
// if f, ok := w.(http.Flusher); ok {
// f.Flush()
// }
}
希望对你有帮助!
英文:
Came across this link: https://stackoverflow.com/questions/66931877/handle-rest-requests-in-golang-grpc-server/73026116#73026116
I am trying to do something very similar to the above described in the link. But instead of simply logging information, I'm trying to pass the variable obtained from the HTTP request onto the RPC call.
Is this possible? The reason it has to be a RPC call is that the bi-directional streaming is done between the grpc server and client and the data has to be processed back to the user who made the HTTP request.
func (s * Server) ConnectAndStream(input *Input, channelStream TestApiService_ConnectAndStreamServer) error {
// TO-DO: This Id has to come from http request
var id int32 = 1234566
// id := a.ConnectAndExchange
log.Println("Id from sam user ", id)
// var id int32 = 1234566
for i := 1; i <= 2; i++ {
id += 1
log.Println("Speed Server is sending data : ", id)
channelStream.Send(&Input{Id: id})
}
for i := 1; i <= 2; i++ {
log.Println("now time to receive")
client_response, err := channelStream.Recv()
log.Println("Response from samd client : ", client_response.Id)
if err != nil {
log.Println("Error while receiving from samd : ", err)
}
}
return nil
}
In-line code comment: the id is hardcoded currently and needs to be obtained from the http request.
Update: Following the suggestion here is my attempt, also modified the RPC function to accept an input so I am able to pass it from HTTP request.
func main() {
go runGrpc() // this listens to incoming connections & registers the endpoint for grpc server
log.Printf("*------ Waiting for requests from SAM users ------*")
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/exchangeId/{test_id}", ConnectAndExchange).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", router))
}
func (s * Server) ConnectAndExchange(w http.ResponseWriter, r *http.Request){
vars := mux.Vars(r)
test_id, _ := strconv.Atoi(vars["test_id"])
log.Println("Test id request from user : ", test_id)
// Guess: need to enclose this in a go routine since when the
test_id is input a stream of response is expected
res := s.ConnectAndStream(test_id)
// Process response to user
// w.Write(res)
// if f, ok := w.(http.Flusher); ok {
// f.Flush()
// }
}
答案1
得分: 1
现在我更好地理解你想要实现的流程了。你的HTTP处理程序方法可以通过http.ResponseWriter
发出对服务器的GRPC调用,并将响应返回。
为了简单起见,我使用了https://github.com/grpc/grpc-go/tree/master/examples/helloworld上的hello world GRPC示例。
运行下面的代码示例,并访问http://localhost:1000/exchangeId/Test
将显示以下输出:
Starting
*------ Waiting for http requests from users on port 1000 ------*
server listening at 127.0.0.1:1001
Test id request from user : Test
Server Received: Test
Greeting: Hello Test
代码示例:
import (
"context"
"log"
"net"
"net/http"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"github.com/gorilla/mux"
)
var (
grpcserver = "localhost:1001"
)
func main() {
log.Print("Starting")
go StartGrpcServer()
log.Printf("*------ Waiting for http requests from users on port 1000 ------*")
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/exchangeId/{test_id}", ConnectAndExchange).Methods("GET")
log.Fatal(http.ListenAndServe(":1000", router))
}
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Server Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func StartGrpcServer() {
lis, err := net.Listen("tcp", grpcserver)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func ConnectAndExchange(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
test_id := vars["test_id"]
log.Println("Test id request from user : ", test_id)
// Set up a connection to the server.
conn, err := grpc.Dial(grpcserver, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := c.SayHello(ctx, &pb.HelloRequest{Name: test_id})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", resp.GetMessage())
w.Write([]byte(resp.GetMessage()))
}
英文:
Now I understand better the flow that you are trying to achieve. Your http handler method can make the outgoing GRPC call to the server and return the response back via the http.ResponseWriter
.
For simplicity I have used the hello world GRPC example on https://github.com/grpc/grpc-go/tree/master/examples/helloworld
Running the code sample below and hitting http://localhost:1000/exchangeId/Test
will show the output
Starting
*------ Waiting for http requests from users on port 1000 ------*
server listening at 127.0.0.1:1001
Test id request from user : Test
Server Received: Test
Greeting: Hello Test
Code sample:
import (
"context"
"log"
"net"
"net/http"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"github.com/gorilla/mux"
)
var (
grpcserver = "localhost:1001"
)
func main() {
log.Print("Starting")
go StartGrpcServer()
log.Printf("*------ Waiting for http requests from users on port 1000 ------*")
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/exchangeId/{test_id}", ConnectAndExchange).Methods("GET")
log.Fatal(http.ListenAndServe(":1000", router))
}
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Server Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func StartGrpcServer() {
lis, err := net.Listen("tcp", grpcserver)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
func ConnectAndExchange(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
test_id := vars["test_id"]
log.Println("Test id request from user : ", test_id)
// Set up a connection to the server.
conn, err := grpc.Dial(grpcserver, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
resp, err := c.SayHello(ctx, &pb.HelloRequest{Name: test_id})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", resp.GetMessage())
w.Write([]byte(resp.GetMessage()))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论