0

我有一个 GO Post API 端点,在处理程序中有一个有点耗时的任务(当我在本地运行时,时间甚至可能是2 分钟)。

在我的 FE 中,我调用 API 一次,它只触发一次(在网络选项卡中,没有多个请求)(1)。API调用的运行时间不同,因为它是根据一些动态数据运行的。但是在 API 端,调用需要一些时间并且成功,但没有发送响应(在 FE 端仍然Pending )。然后处理程序立即再次运行(仍然在 FE 端等待)并且逻辑再次运行。因此,由于逻辑原因,由于它已经运行,因此它失败了。然后该响应作为来自 FE (1)的请求的响应返回。所以,逻辑是成功的,数据库被更新了,但是响应发送了一个错误。

这是由于超时问题吗?如果是这样,我怎样才能解决这个问题?

我使用 go-chi 作为 GO 框架并为 FE 做出反应。

r := chi.NewRouter()

r = helpers.AttachLoggerMiddleware(r, pretty)
r.Route("/apps", func(r chi.Router) {
    r.Post("/{id}/clone", service.Clone)
}


func (s *Service) Clone(w http.ResponseWriter, r *http.Request) {     
    fmt.Println("Calling Clone !!")
    //logic
}

这是如何配置 API 方法的一些示例

4

1 回答 1

0

您应该重新设计您的方法以使用长轮询机制,使用WebSosketJSON 流也将是一个选项。

一点解释:

您有一项耗时的任务(需要 2 分钟,如果您的应用程序有更多负载,可以肯定它可能需要更多时间)。因此,如果您将使用简单的 Request-Respons 方法,则会因为超时问题而出错。

因此,使用建议的方法将更适合您的情况。

让我们看一下 WebSocket 示例:

在你的 go 代码中,你会有类似的东西(这只是一个例子,我不知道 chi 和 usegithub.com/gorilla/websocket和 vanilla net/http,但我很确定你可以用 chi 做同样的事情):

package main

import (
    "fmt"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "time"
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func main() {
    http.HandleFunc("/ws", wsHandler)
    
    panic(http.ListenAndServe(":8080", nil))
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println(err)
        return
    }
    
    if err != nil {
        http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
    }
    
    go echo(conn)
}

func echo(conn *websocket.Conn) {
    defer conn.Close()
    m := ""
    
    err := conn.ReadJSON(&m)
    if err != nil {
        fmt.Println("Error reading json", err)
    }
    
    // receive some data from your reactjs
    fmt.Printf("Got message: %#v\n", m)
    
    om := struct {
        mes string
    }{
        mes: "Send to client",
    }
    
    // send some data
    if err = conn.WriteJSON(om); err != nil {
        fmt.Println(err)
    }
    
    // do some work in 2 min
    time.Sleep(120 * time.Second)
    
    // send some data
    if err = conn.WriteJSON(om); err != nil {
        fmt.Println(err)
    }
}

在您的 react js 应用程序中,您将拥有如下内容:

import React, { useState } from "react";

function  App() {
  let isDone = false;
  const messages = []
  const ws = new WebSocket("wss://localhost:8080/ws");

  const apiCall = {
    mes: "Your json for server" 
  };

  ws.onopen = (event) => {
    ws.send(JSON.stringify(apiCall));
  };

  ws.onmessage = function (event) {
    const json = JSON.parse(event.data);
    messages.push(json)
    } catch (err) {
      console.log(err);
    }
  };
  
  ws.onclose = function (event) {
    isDone = true
  };



  const mess = messages.map((item) => {
    return (
      <div>
        <p> {item}</p>
      </div>
    );
  });

  return (
       <div>
           <div>{mess}</div>
           <div> is work done?: {isDone}</div> 
       </div> 
   );
}

export default  App;

在此示例中,我们向服务器发送一些信息并开始等待工作何时完成(关闭isDone = truews),同时接收一些消息(在您的情况下可能不需要)。

使用长轮询和 JSON 流来实现这个想法也是如此(我认为你很容易在互联网上找到一些东西:))

于 2022-01-21T10:15:57.670 回答