Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【错误与需求】Nginx与chunked模式 #618

Open
CsVeryLoveXieWenLi opened this issue Jul 24, 2024 · 16 comments
Open

【错误与需求】Nginx与chunked模式 #618

CsVeryLoveXieWenLi opened this issue Jul 24, 2024 · 16 comments

Comments

@CsVeryLoveXieWenLi
Copy link

CsVeryLoveXieWenLi commented Jul 24, 2024

1. 使用环境

OS:Linux armbian 5.4.279-ophub #1 SMP PREEMPT Wed Jul 10 10:53:39 EDT 2024 aarch64 aarch64 aarch64 GNU/Linux
Version:Cinatra-0.9.2

2. 问题代码

#ifdef _WIN32
#define _WIN32_WINNT 0x0601
#endif

#define BUFFER_SIZE 1024 * 100


#include <cinatra.hpp>


using namespace cinatra;


// Tools
async_simple::coro::Lazy<void> sends(coro_http_response& response, std::filesystem::path& path) {
    // Type
    std::string      _path     = path.string();
    std::string_view extension = get_extension(_path);
    std::string_view mime      = get_mime_type(extension);

    response.add_header("content-type", mime.data());


    // Format
    response.set_format_type(format_type::chunked);


    // Open
    coro_io::coro_file file{};
    file.open(_path, std::ios::in);


    // Read And Send
    bool        ok;
    bool        end;
    std::string buffer;

    // reserve
    buffer.reserve(BUFFER_SIZE);

    // start
    ok = co_await response.get_conn()->begin_chunked();
    if (!ok) {
        file.close();
        co_return;
    }

    // read
    while (true) {
        auto [_, size] = co_await file.async_read(buffer.data(), BUFFER_SIZE);

        end = file.eof();
        ok  = co_await response.get_conn()->write_chunked(std::string_view(buffer.data(), size), end);

        if (!ok || end) {
            file.close();
            co_return;
        }
    }
}


// Main
int main(int argc, char* argv[]) {
    // Command
    if (argc != 5) {
        printf("Use: StaticWeb [cpus] [host] [port] [dir]\n");
        return 1;
    }

    // Static
    std::filesystem::path dir(argv[4]);
    std::filesystem::path nfound = dir / "404.html";


    // Create
    coro_http_server server(atoi(argv[1]), atoi(argv[3]), argv[2], true);


    // Default
    server.set_default_handler(
        [&](coro_http_request& request, coro_http_response& response) -> async_simple::coro::Lazy<void> {
            // Is Get Method?
            if (request.get_method() != "GET" || request.is_upgrade()) co_return;


            // Get Path
            std::string   _pathname = code_utils::url_decode(request.get_url()).substr(1);
            std::u8string pathname(_pathname.begin(), _pathname.end());


            // Src File
            std::filesystem::path vpath = dir / pathname;


            // Not Exixts
            if (!std::filesystem::exists(vpath)) vpath = nfound;


            // Not Dir
            if (!std::filesystem::is_directory(vpath)) {
                co_await sends(response, vpath);
                co_return;
            }

            // Is Dir
            vpath /= "index.html";

            std::filesystem::exists(vpath) ? co_await sends(response, vpath)
                                           : response.set_status_and_content_view(status_type::method_not_allowed, "");
        }
    );


    // Run
    return server.sync_start().value();
}

4. Nginx配置

# 反代主页
server
{
    listen [::]:80;
    server_name xxx.xxx.cn;
    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:83;
        chunked_transfer_encoding on;
    }
}

5. 问题描述

当我使用chunked模式传输的时候,会直接被Nginx关闭socket?我使用了Nginx作为反向代理。

为何我会这么认为?我使用curl访问127.0.0.1:83的时候一切正常,会返回请求的相应文件。

当我使用Nginx,访问xxx.xxx.cn,被转发到127.0.0.1:83,通过Nginx的逻辑进行访问,会出现 “async_write error: Bad file descriptor”。

socket也是一个文件描述符(?)其中唯一的写入只有write_chunked,不测试set_status_and_content_view。

这是我的项目,如有疑问请访问:https://github.com/CsVeryLoveXieWenLi/StaticWeb

6. 其他

我并未测试直接返回,不使用chunked模式,但是我觉得就是这样,请稍等我测试直接返回。

我们是否应该出一个流式访问而非chunked模式,相关的API接口?不应该读取保存全部到内存。

@CsVeryLoveXieWenLi
Copy link
Author

还是我写的有问题,我不太懂,抱歉。

@qicosmos
Copy link
Owner

稍晚点看一下。

@CsVeryLoveXieWenLi
Copy link
Author

CsVeryLoveXieWenLi commented Jul 25, 2024

我使用了读取全部到内存就正常了,不排除是我代码写的有问题,可能比较隐晦没看出来。

// Tools
async_simple::coro::Lazy<void> sends(coro_http_response& response, std::filesystem::path& path) {
    // Type
    std::string      _path     = path.string();
    std::string_view extension = get_extension(_path);
    std::string_view mime      = get_mime_type(extension);

    response.add_header("content-type", mime.data());


    // Open
    std::ifstream file;
    file.open(path, std::ios::binary);

    if (!file.is_open()) co_return;


    // Read And Send
    std::istreambuf_iterator<char> beginf(file);
    std::istreambuf_iterator<char> endf;

    std::string content(beginf, endf);

    // close
    file.close();

    // send
    response.set_status_and_content(status_type::ok, std::move(content));
}

@CsVeryLoveXieWenLi CsVeryLoveXieWenLi changed the title 【错误与需求】Nagix与chunked模式 【错误与需求】Nginx与chunked模式 Jul 25, 2024
@qicosmos
Copy link
Owner

qicosmos commented Jul 25, 2024

你也可以直接使用cinatra的反向代理功能呀

@qicosmos
Copy link
Owner

不需要nginx的

@CsVeryLoveXieWenLi
Copy link
Author

不需要nginx的

貌似不支持域名反代,我一开始确实想用cinatra的。

@qicosmos
Copy link
Owner

应该支持啊

@qicosmos
Copy link
Owner

为啥不行?

@CsVeryLoveXieWenLi
Copy link
Author

啊?不是吧,我没翻到,等我再翻翻。

@CsVeryLoveXieWenLi
Copy link
Author

CsVeryLoveXieWenLi commented Jul 25, 2024

您可能理解错了我的意思,我是说二级域名反向代理。

由于我只有一台服务器,并且不想使用路径,使用二级域名这样更好的标识。

正常情况下,客户端的请求头host地址与请求地址是对应的。通过检测这个,来达成转发。

当然,这是我的理解,反正就是检测域名嘛。

@qicosmos
Copy link
Owner

https://github.com/qicosmos/cinatra/blob/master/tests/test_coro_http_server.cpp#L1441
看下这个例子看是否满足,我理解应该没问题。

@CsVeryLoveXieWenLi
Copy link
Author

CsVeryLoveXieWenLi commented Jul 25, 2024

我想并不满足,我应该说的还是有问题,抱歉。

一个服务器中,转发服务监听0.0.0.0:80(http),还有一个前端视频站服务,监听127.0.0.1:83。

当请求进来的时候,检测该请求的host请求头,从映射表里寻找。

如果host是video.big.cn,那么转发到本地的127.0.0.1:83(或者多个负载均衡)。

而不是监听端口,检测客户端请求的urlpath,如果urlpath是,/video,就转发到127.0.0.1:83。

其实除了检测请求头的host,我也不知道怎么检测。只要确定,用户是访问了video.big.cn,想要进到视频站就对了。

@qicosmos
Copy link
Owner

稍微改一下代码就好了,晚点给个例子。

@CsVeryLoveXieWenLi
Copy link
Author

好的,那么流式的写入接口可以添加么?我看了一下源码,感觉不好实现(?)

@qicosmos
Copy link
Owner

有点忙,等晚点吧。不会麻烦的,事实上已经有一些基于cinata的网关产品在生产环境下跑了。

@CsVeryLoveXieWenLi
Copy link
Author

好的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants