首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >服务器发送的事件未从自制服务器接收到

服务器发送的事件未从自制服务器接收到
EN

Stack Overflow用户
提问于 2021-02-20 22:05:44
回答 1查看 110关注 0票数 0

我正在尝试使用围绕libuv的包装器uvw来设置web服务器。我已经让服务器达到了一个点,在那里我可以发送简单的响应,并且它可以正常工作。我想添加SSE路由,但无论我尝试什么,都无法使浏览器正确接收我试图发送的事件。关于上交所,我是不是漏掉了什么?我已经成功地将延迟添加到正常的html响应中,但无论我做什么更改,客户端(我使用的是Javascripts )不会报告任何事件,开发人员工具的网络选项卡也不会。

我的代码: main.cpp

代码语言:javascript
复制
#include <memory>
#include <map>
#include <uvw.hpp>
#include <functional>
#include <iostream>
#include <fstream>
    
using HttpRequestHandler = std::function<void(std::string_view header, uvw::TCPHandle& socket)>;

// Global (yeah) registry of http request handlers
std::map<std::string, HttpRequestHandler> httpHandlers;

// Utility functions for sending messages to tcp sockets 
void send (uvw::TCPHandle& target, std::string message) {
    target.tryWrite(message.data(), message.size());
}
void send (std::shared_ptr<uvw::TCPHandle> target, std::string message) {
    send(*target, message);
}

int main () {
    // Create the loop
    auto loop = uvw::Loop::getDefault();
    // Make a handler for our server
    auto tcp = loop->resource<uvw::TCPHandle>();

    // Setup logic for incoming connections
    tcp->on<uvw::ListenEvent>([](const uvw::ListenEvent& event, uvw::TCPHandle& server){
        std::shared_ptr<uvw::TCPHandle> connection = server.loop().resource<uvw::TCPHandle>();

        // Setup dealing with the other side disconnecting
        connection->once<uvw::EndEvent>([](const auto&, uvw::TCPHandle& connection){ connection.close(); });
        // Setup loging errors
        connection->on<uvw::ErrorEvent>([](const uvw::ErrorEvent& err, uvw::TCPHandle& connection) {
            std::cerr << "Error @ " << connection.sock().ip << ':' << connection.sock().port << "; Message: "
                << err.what() << '\n';
        });

        // Setup dealing with the request
        connection->on<uvw::DataEvent>([](const uvw::DataEvent& event, uvw::TCPHandle& connection){
            std::string_view msg {event.data.get(), event.length};
            
            // Extract the request path
            const auto firstSpaceIndex = msg.find(' ');
            const auto secondSpaceIndex = msg.find(' ', firstSpaceIndex+1);
            std::string_view requestPath {msg.data()+firstSpaceIndex+1, secondSpaceIndex-firstSpaceIndex-1};

            // TODO: Authenticate the other side

            // Use the apropriate handler
            if (httpHandlers.contains(std::string(requestPath))) {
                httpHandlers.at(std::string(requestPath))(msg, connection);
            }
            // Or if there's no good handler, just 404
            else {
                std::string http404Message = "HTTP/1.1 404 Not Found\r\n\r\n";
                connection.write(http404Message.data(), http404Message.size());
                connection.close();
            }
        });

        // Connect the prepared connection object with an actual request
        server.accept(*connection);
        // Start reading the data we're getting
        connection->read();
    });

    // Select a port
    tcp->bind("127.0.0.1", 4242);
    // and connect to it
    tcp->listen();

    // Open the file with the response of our index page
    std::ifstream indexPage ("resources/page.html");
    std::string indexPageMessage {std::istreambuf_iterator<char>(indexPage), std::istreambuf_iterator<char>()};

    // Register the index handler
    httpHandlers["/"] = [message = indexPageMessage](std::string_view header, uvw::TCPHandle& socket) -> void {
        socket.write(const_cast<char*>(message.data()), static_cast<unsigned int>(message.size()));
        socket.close();
    };

    // Register the SSE route handler
    httpHandlers["/gameEvents"] = [](std::string_view header, uvw::TCPHandle& socket) -> void {
        std::cout << "Connecting to gameEvents\n";
        
        // Setup the timer
        auto timer = socket.loop().resource<uvw::TimerHandle>();

        // Send the headerss
        send(socket, 
            "HTTP/1.1 200 OK\r\n"
            "Cache-Control: no-cache\r\n"
            "Content-Type: text/event-stream\r\n"
            "\r\n\r\n"
        );

        // Deal with other side closing
        socket.on<uvw::CloseEvent>([timer = timer->shared_from_this()](auto& ev, auto& socket) {
            timer->close();
            socket.close();
        });

        // React to timer ticks
        timer->on<uvw::TimerEvent>([socket = socket.shared_from_this()](auto& event, auto& timer){
            if(socket->writable()) {
                std::cout << "timer sending timer event\n";
                send(socket, "event: timer\n");
            } else {
                std::cout << "timer encountered unwriteable socket, ignoring for now\n";
            }
        });

        // Trigger the above handler every 5 seconds
        timer->start(uvw::TimerHandle::Time{510}, uvw::TimerHandle::Time{5000});
    };

    // Start the show
    loop->run();
    // Cleanup after ourselfs
    tcp->close();
}

和resources/page.html

代码语言:javascript
复制
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Page</title>
</head>
<body>
    <h2>Hello, world!</h2>
    <script>
        const myEventStream = new EventSource("/gameEvents");
        myEventStream.addEventListener('message', ev => {
            console.log('sse event');
        })
    </script>
</body>
</html>
EN

回答 1

Stack Overflow用户

发布于 2021-02-21 04:17:37

发现了问题,我是个笨蛋,我没有把我的换行符发对。这条线

代码语言:javascript
复制
send(socket, "event: timer\n")

而不应该是

代码语言:javascript
复制
send(socket, "event: timer\r\n\r\n")

我没有发送额外的换行符来表示事件的结束,所以对于浏览器,我只发送了一个超长的事件。另外,我的javascript也坏了-- myEventStream.addEventListener('message', ...)会监听名为'message‘的事件,而不会对任何消息做出反应。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66292421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档