PHP ob_get_length 似乎 return 不正确的值

PHP ob_get_length seems to return incorrect value

我有一个函数应该 return JSON 响应客户端,然后在不锁定客户端的情况下继续处理,这似乎工作正常,除非我添加 Content-Length header(我想这样做以确保释放客户端)。 函数为:

function replyAndCarryOn($responseText){
    ignore_user_abort(true);//stop apache killing php
    ob_start();//start buffer output
    echo $responseText;
    session_write_close();//close session file on server side to avoid blocking other requests
    header("Content-Encoding: none");
    header('Content-Type: application/json; charset=utf-8');                   
    header("Content-Length: ".ob_get_length());
    header("Connection: close");
    ob_end_flush();
    flush();
}

这工作正常,除了 JSON 字符串 return 被截断到浏览器,因为 Content-Length 是错误的。例如下面的字符串

{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1}, "uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"Payment"}

将显示为:

{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1},{"uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"

我可以将 Content-Length header 留在外面,apache (2.2) 会自动添加 'Transfer-Encoding:"chunked"' header 这似乎有效,但我想要深入了解为什么 ob_get_length 没有 return 我需要的值,我知道如果启用 gzip,它会产生太长的结果,但我看到值是相反的过短。

所以我想知道:

a) 我在获取内容长度时做错了什么?

b) 遗漏它有什么问题吗?

根据@Xyv 的评论,服务器似乎在输出字符串前输出了一个换行符和八个空格,但这不包括在ob_get_length return 中。令人尴尬的是,它原来是一个马车 return 并且在第一个 php 标签之前以某种方式添加了八个空格。

我想我 post 将此作为答案以提高可读性。

也许首先捕获输出,然后生成 headers,然后 body?

对我来说这个例子有效:

<?php
function replyAndCarryOn($responseText){
    ignore_user_abort(true);//stop apache killing php
    ob_flush( );
    ob_start( );//start buffer output
    echo $responseText;
    session_write_close();//close session file on server side to avoid blocking other requests
    header("Content-Encoding: none");
    header('Content-Type: application/json; charset=utf-8');                   
    header("Content-Length: ".ob_get_length());
    header("Connection: close");
    echo ob_get_flush();
    flush();
}


replyAndCarryOn(  '{"result":"AUTH","authList":[{"uid":"Adam","gid":"Users","authid":1}, "uid":"Admin","gid":"Admin","authid":2},{"uid":"George","gid":"Users","authid":3},{"uid":"test","gid":"Users","authid":4}],"id":"Payment"}'  );
?>

更新 重要的是要知道 ob_start() 应该在输出任何 body 之前。缓冲区将丢失此数据,因此它可能不会被计算在内。我不是输出缓冲方面的专家,但请确保将 ob_start 放在脚本的开头,这样就很难(呃)出错。 (所以要小心在初始 <?php 之前放置空格 and/or 制表符)。