Vue实现Laravel应用中textarea无缓冲实时更新的问题
解决Vue实时展示PHP流式输出的问题
你的核心问题在于axios默认会等待整个HTTP响应完成后才触发回调,没法处理PHP端的增量输出。要实现实时更新,我们需要换用支持流式响应监听的请求方式,同时确保PHP端的输出配置完全正确。下面是分步解决方案:
一、修改Vue的请求逻辑:用XMLHttpRequest替代axios
XMLHttpRequest提供了onprogress事件,可以在数据逐步返回时实时捕获内容。修改你的onCommand方法:
onCommand: function onCommand(task, websiteid) { const _this3 = this; const xhr = new XMLHttpRequest(); xhr.open('POST', '/' + task + '/' + websiteid, true); // 必须设置Laravel需要的CSRF Token const csrfToken = document.querySelector('meta[name="csrf-token"]').content; xhr.setRequestHeader('X-CSRF-TOKEN', csrfToken); xhr.setRequestHeader('Content-Type', 'application/json'); // 实时监听数据返回 xhr.onprogress = function() { // responseText会累积所有已接收的内容,计算新增部分避免重复添加 const newContent = xhr.responseText.substring(_this3.comment_body.length); if (newContent) { _this3.comment_body += newContent; } }; // 请求完成后的收尾处理 xhr.onload = function() { if (xhr.status === 200) { _this3.comment_body += '\n|------ ' + task + ' 执行完成 ----|'; } else { try { const errorData = JSON.parse(xhr.responseText); _this3.errors.record(errorData.errors); } catch (e) { _this3.errors.record({ general: '请求执行失败' }); } } }; xhr.onerror = function() { _this3.errors.record({ general: '网络请求出错' }); }; // 发送请求数据(和之前axios的payload一致) xhr.send(JSON.stringify(this.$data)); }
同时别忘了给textarea加上Vue的双向绑定,否则数据更新不会同步到视图:
<textarea v-model="comment_body" name="comment_body" id="update-comment" placeholder="output goes here, feel free to notate" rows="10" class="update-comment"></textarea>
二、修复PHP端的输出配置
确保PHP的输出完全无缓冲,并且禁用服务器的压缩(压缩会强制缓冲内容):
public function yourCommandHandler(Request $request) { // 禁用缓存与压缩,这一步是关键! header('Cache-Control: no-cache, no-store, must-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); header('Content-Type: text/plain; charset=utf-8'); // 禁用Apache的gzip压缩(如果服务器开启了的话) if (function_exists('apache_setenv')) { apache_setenv('no-gzip', 1); } ini_set('zlib.output_compression', 0); // 清空所有已存在的输出缓冲 ob_end_clean(); var_dump( "something1"); ob_flush(); flush(); // 立即发送内容 echo "$command"; ob_flush(); flush(); $this->process_wrapper($command); echo "something4"; ob_flush(); flush(); } public function process_wrapper($cmd, $data = null) { $descr = array( 0 => array( 'pipe', 'r' ) , 1 => array( 'pipe', 'w' ) , 2 => array( 'pipe', 'w' ) ); $pipes = array(); echo "something2"; ob_flush(); flush(); echo "something3"; ob_flush(); flush(); $process = proc_open($cmd, $descr, $pipes, realpath('./'), array()); if (is_resource($process)) { while ($f = fgets($pipes[1])) { echo $f; ob_flush(); flush(); // 加个微小延迟,避免浏览器合并小输出块(可选但推荐) usleep(10000); // 10毫秒 } proc_close($process); } }
三、关键注意事项
- 服务器层面的缓冲:如果用Nginx,需要在对应location配置中添加
proxy_buffering off;,否则Nginx会缓冲响应内容再发给浏览器。 - 浏览器缓冲:部分浏览器会累积一定量的内容才更新视图,输出换行符或者少量空白字符可以触发即时更新。
- CSRF Token:Laravel的POST请求必须携带CSRF Token,别忘了在页面头部添加
<meta name="csrf-token" content="{{ csrf_token() }}">。
内容的提问来源于stack exchange,提问作者Zendasi
相关产品推荐
相关产品推荐

