【问题标题】:How do I stream content with Yaws?如何使用 Yaws 流式传输内容?
【发布时间】:2012-02-13 08:00:32
【问题描述】:

我读到了Yaws: streaming data to the client。我创建了一个如下所示的简单示例,但它不起作用。我收到一个错误,进程正在终止。

这是我的 yaws 文件:

<erl>
out(A) ->
    Self = self(),  
    spawn(fun() ->
        yaws_api:stream_chunk_deliver_blocking(Self, "Hello"),
        yaws_api:stream_chunk_end(Self, "Thanks"),
        exit(normal)
    end),
    {streamcontent, "text/html; charset=utf-8", "First\r\n"}.
</erl>

我也试过yaws_api:stream_chunk_deliver/2,但我得到了同样的错误。这是我在命令提示符中收到的错误消息:

=ERROR REPORT==== 13-Feb-2012::09:23:30 ===
Error in process <0.117.0> with exit value: {undef,[{yaws_api,stream_chunk_end,[
\n"],[]}]}"Thanks

1>
=ERROR REPORT==== 13-Feb-2012::09:24:00 ===
Yaws process died: {stream_timeout,
                       [{yaws_server,stream_loop_send,5,
                            [{file,"yaws_server.erl"},{line,2821}]},
                        {yaws_server,aloop,3,
                            [{file,"yaws_server.erl"},{line,1167}]},
                        {yaws_server,acceptor0,2,
                            [{file,"yaws_server.erl"},{line,1025}]},
                        {proc_lib,init_p_do_apply,3,
                            [{file,"proc_lib.erl"},{line,227}]}]}
1>

最后一个块似乎没有发送到客户端:

HTTP/1.1 200 OK
Server: Yaws 1.92
Date: Mon, 13 Feb 2012 07:31:18 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked

7
First

7
Hello

这是我使用的 JavaScript 客户端代码(仅适用于 IE8 和 IE9),使用 XDomainRequest

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script>
window.onload = function() {
    var el = document.getElementById("requestbutton");
    if(el.attachEvent) {
        el.attachEvent('onclick', doXDR);
    }
}

function writeStatus(message) {
    var html = document.createElement("div");
    html.setAttribute("class", "message");
    html.innerHTML = message;
    document.getElementById("status").appendChild(html);
}

function doXDR() {
    if(!window.XDomainRequest) {
        writeStatus("No XDR support in your browser");
        return;
    }

    writeStatus("Beginning XDR");
    try {
        var xdr = new XDomainRequest();
        xdr.open("GET", "http://localhost:8090/stream.yaws");
        xdr.send();
        xdr.onload = function() {
            writeStatus("XDR response: " + xdr.responseText);
        };
        xdr.onerror = function() {
            writeStatus("XDR error");
        };
        xdr.onprogress = function() {
            writeStatus("XDR intermediate: " + xdr.responseText);
        };
    } catch (e) {
        writeStatus("XDR Exception: " + e);
    }
}
</script>
</head>
<body>
<h1>Test page</h1>
<button id="requestbutton">Send request</button><br>
<div id="status"></div>
</body>
</html>

在 JavaScript 客户端上,调用 xdr.onerror = function() 方法。客户端不应在此示例中显示任何数据,因为它需要 2k 前奏,但应该按照我的理解发送。


更新

在修复了 Steve Vinoski 指出的 Erlang 问题并删除了我的数据上的 \r\n 之后,Yaws 服务器发送了正确的数据。但我仍然在 JavaScript 客户端上收到 xdr.onerror = function() 错误。看来我需要在响应Access-Control-Allow-Origin: * 中添加另一个标头,如XDomainRequest Object 中所述:

该文档将通过发送一个带有源值的 Origin 标头从域的服务器请求数据。只有当服务器以 *Access-Control-Allow-Origin 标头或请求文档的确切 URL 响应时,它才会完成连接。此行为是万维网联盟 (W3C) 的 Web 应用程序工作组关于 XDomainRequest 对象与之集成的客户端跨域通信框架草案的一部分。

如何将此标头添加到 HTTP 响应中?看来我只能在返回值中设置 MIME 类型:{streamcontent, MimeType, FirstChunk}?

【问题讨论】:

    标签: internet-explorer erlang http-streaming yaws xdomainrequest


    【解决方案1】:

    每当您看到 undef 错误时,就像您在上面显示的那样:

    Error in process <0.117.0> with exit value: {undef,[{yaws_api,stream_chunk_end,
    

    这意味着您正在调用不在加载路径上的模块中的函数,或者正在调用不存在的函数。在您的代码中,您调用的是不存在的yaws_api:stream_chunK_end/2。你想要的是yaws_api:stream_chunk_end/1。将您的代码更改为以下内容:

    <erl>
      out(A) ->
        Self = self(),  
          spawn(fun() ->
            yaws_api:stream_chunk_deliver_blocking(Self, "Hello\r\n"),
            yaws_api:stream_chunk_deliver_blocking(Self, "Thanks\r\n"),
            yaws_api:stream_chunk_end(Self),
            exit(normal)
          end),
        {streamcontent, "text/html; charset=utf-8", "First\r\n"}.
    </erl>
    

    然后我认为你的例子会很好。

    更新:

    要回答问题的新部分,请使用列表返回值而不是单个元组,确保 streamcontent 元组在列表中的最后:

    [{header, {"Access-Control-Allow-Origin", "*"}},
     {streamcontent, "text/html; charset=utf-8", "First"}].
    

    【讨论】:

    • +1 谢谢,这解决了我的 Erlang 问题。但是,看来我必须在 HTTP 响应中添加另一个 HTTP 标头。而且我不明白我应该怎么做,请参阅我的更新。有没有更通用的方法来添加标题?
    • 我使用这个变通方法返回值:{streamcontent, "text/html; charset=utf-8\r\nAccess-Control-Allow-Origin: *", "First"}. 现在它工作正常。这是 IE8 和 IE9 中 WebSockets 的一个很好的后备方案。谢谢。
    • 查看我的答案的更新,了解如何正确设置标题。
    猜你喜欢
    • 2015-12-30
    • 2016-10-03
    • 2010-11-12
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 2015-03-07
    • 1970-01-01
    相关资源
    最近更新 更多