Триггерное событие отправки сервера каждые 2 секунды в golang

Мой серверный код на golang

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/rs/cors"
)

func main() {
    mux := http.NewServeMux();

    mux.HandleFunc("/sse" , handleSse)

    c  := cors.New(cors.Options{
            AllowedOrigins:   []string{"*"},
            AllowedMethods:   []string{http.MethodGet, http.MethodPost,
                        http.MethodDelete , http.MethodPut},
            AllowCredentials: true,
        })

    handler := c.Handler(mux)

    log.Fatal(http.ListenAndServe(":6969" , handler))
}

func handleSse(w http.ResponseWriter , r * http.Request){

    w.Header().Set("Content-type","text/event-stream")
    w.Header().Set("Cache-Control","no-cache")
    w.Header().Set("Connection","keep-alive")

    f , ok := w.(http.Flusher);
    if !ok{
    http.Error( w , "SSE not supported" ,
        http.StatusBadRequest)
    return;
    }

    fmt.Fprintf(w,"data:%v\n\n","sample data");
    f.Flush();
}

клиентский код

<!DOCTYPE html>
<html lang = "en">
  <head>
    <title>SSE</title>
  </head>
  <body>
    SSE running
    <script>
    const event = new EventSource("http://localhost:6969/sse");
    event.onmessage = () =>{
        console.info("this dude is slow");
    };
    </script>
  </body>
</html>

У меня проблема в том, что на вкладке «Сеть» новый текстовый поток или ответ приходит через 5,4 секунды. Я хочу, чтобы сервер отправлял ответ каждые 2 секунды Я пробовал бесконечный цикл for в серверном коде, который показан в каком-то руководстве, и он не работает.

РЕДАКТИРОВАТЬ : Функция обработчика цикла for


func handleSse(w http.ResponseWriter , r * http.Request){

    w.Header().Set("Content-type","text/event-stream")
    w.Header().Set("Cache-Control","no-cache")
    w.Header().Set("Connection","keep-alive")
    w.WriteHeader(http.StatusOK)

    f , ok := w.(http.Flusher);
    if !ok{
    http.Error( w , "SSE not supported , IE6 bruh" ,
        http.StatusBadRequest)
    return;
    }

    for i := 0 ; i < 10 ; i++{
        fmt.Fprintln(w,"retry : 1000"); //This line also doesnot help
        fmt.Fprintf(w,"data :%v\n\n","Sorry");
        f.Flush();
    //time.Sleep(1 * time.Second) //This line increase delay to 25 secs
    }
}

«Я пробовал бесконечный цикл for в серверном коде» — покажите нам это. Ваш текущий код отправит одно сообщение, а затем закроет соединение (поэтому задержка между сообщениями — это время повторного соединения ; вы можете доказать это, добавив fmt.Fprintln(w, "retry: 1000") над строкой, которая отправляет data). С помощью SSE вы хотите поддерживать соединение открытым — хороший пример см. в этом ответе.

Brits 07.07.2024 23:32

Я пытался указать время переподключения, но это не помогает. Задержка по-прежнему составляет 5 секунд. Я также отредактировал вопрос и добавил код цикла.

yahya kamran 08.07.2024 12:03
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Расстояние важно — fmt.Fprintf(w,"data :%v\n\n","Sorry"); не подойдет; так и должно быть fmt.Fprintf(w, "data:%v\n\n", "Sorry").

Ниже приведен рабочий пример; он отправит 10 сообщений, а затем разорвет соединение. Поскольку он также устанавливает retry: 10000 (повторите попытку 10000ms, т. е. 10s), браузер повторно подключится через 10 секунд (и получит еще 10 сообщений с интервалом в секунду). Обратите внимание, что я добавил к сообщениям метку времени (что делает вывод более понятным, поскольку браузеры имеют тенденцию объединять одинаковые строки вывода).

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/rs/cors"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
        w.Write([]byte(`<!DOCTYPE html>
<html lang = "en">
  <head>
    <title>SSE</title>
  </head>
  <body>
    SSE running
    <script>
    const event = new EventSource("http://localhost:6969/sse");
    event.onmessage = () =>{
        console.info("this dude is slow");
    };
    </script>
  </body>
</html>
`))
    })

    mux.HandleFunc("/sse", handleSse)

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowedMethods: []string{http.MethodGet, http.MethodPost,
            http.MethodDelete, http.MethodPut},
        AllowCredentials: true,
    })

    handler := c.Handler(mux)

    log.Fatal(http.ListenAndServe(":6969", handler))
}

func handleSse(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("Content-type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")
    w.WriteHeader(http.StatusOK)

    f, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "SSE not supported , IE6 bruh",
            http.StatusBadRequest)
        return
    }

    for i := 0; i < 10; i++ {
        fmt.Fprintln(w, "retry: 10000") // This means that after the connection drops the browser will wait 10 seconds before reconnecting
        fmt.Fprintf(w, "data:%v\n\n", "Sorry")
        f.Flush()
        time.Sleep(1 * time.Second) // This means a message will be sent every second (until 10 have been sent when the connection will drop)
    }
}

В реальной системе обработчик (handleSse в данном случае) вполне может выйти только в том случае, если при записи он получит ошибку, в противном случае он останется активным, пока программа работает. Такой обработчик будет откуда-то получать данные, возможно, по каналу, и отправлять их браузеру.

Обратите внимание: мое первоначальное предложение добавить fmt.Fprintln(w, "retry: 1000") было попыткой прояснить происходящее. С вашим исходным кодом браузер подключался, получал одно сообщение (после чего сервер разрывал соединение), а затем повторно подключался через 5 секунд (чтобы получить еще одно сообщение...).

В дополнение к ответу @Britis, запускать бесконечное количество раз каждые 2 секунды. Я использую тикер golang и контекст, чтобы остановить цикл в случае отключения клиента или выключения сервера.

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/rs/cors"
)

func main() {
    mux := http.NewServeMux()


    mux.HandleFunc("/sse", handleSse)

    c := cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowedMethods: []string{http.MethodGet, http.MethodPost,
            http.MethodDelete, http.MethodPut},
        AllowCredentials: true,
    })

    handler := c.Handler(mux)

    log.Fatal(http.ListenAndServe(":6969", handler))
}

func handleSse(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("Content-type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")
    w.WriteHeader(http.StatusOK)

    f, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "SSE not supported , IE6 bruh",
            http.StatusBadRequest)
        return
    }

     // Send retry directive to client
    fmt.Fprintln(w, "retry: 10000")
    flusher.Flush()

    // Send events to the client every 2 seconds
    ticker := time.NewTicker(2 * time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-r.Context().Done():
            fmt.Println("The client has disconnected or the server is shutting down"
            return
        case <-ticker.C:
            fmt.Fprintf(w, "data: %v\n\n", "Sorry")
            flusher.Flush()
        }
    }
}

Другие вопросы по теме