Safari浏览器上传Blob至Azure存储报fread()错误求助
Safari浏览器下Blob上传Azure存储报错:
fread(): read of 8192 bytes failed with errno=21 Is a directory 我实现了Blob文件上传至Azure存储的功能,在Chrome、Firefox、Edge等浏览器均可正常运行,但在Safari中持续出现上述错误。
前端JavaScript代码
navigator.mediaDevices.getUserMedia(constraintObj) .then(function(mediaStreamObj) { // 连接媒体流到video元素 let video = document.querySelector('video'); if ("srcObject" in video) { video.srcObject = mediaStreamObj; } else { // 兼容旧版本浏览器 video.src = window.URL.createObjectURL(mediaStreamObj); } // 录制相关监听逻辑 let mediaRecorder = new MediaRecorder(mediaStreamObj); let chunks = []; start.addEventListener('click', (ev) => { $("#vid_media_recorder").prop('muted', false); video.play(); mediaRecorder.start(); console.log(mediaRecorder.state); }) stop.addEventListener('click', (ev) => { mediaRecorder.stop(); console.log(mediaRecorder.state); }); mediaRecorder.ondataavailable = function(ev) { chunks.push(ev.data); } mediaRecorder.onstop = (ev) => { let blob = new Blob(chunks, { 'type': 'video/mp4;' }); chunks = []; let videoURL = window.URL.createObjectURL(blob); var formData = new FormData(); formData.append('blob', blob); $.ajax({ method: "POST", url: "media", headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, data: formData, processData: false, contentType: false, success: function(data) { media_identifier = false; $("#vid_media_recorder").prop('muted', true); alert(data.path_azure); }, error: function(jqXHR, textStatus, errorThrown) { alert(errorThrown); alert(textStatus); alert(JSON.stringify(jqXHR)); } }); } }) .catch(function(err) { console.log(err.name, err.message); });
前端逻辑:通过MediaRecorder录制视频生成Blob文件,停止录制后用FormData封装并通过Ajax提交至后端。
后端Laravel控制器代码
public function store(Request $request) { $path = $request->file('blob')->storeAs( 'test_capture', Str::random(16) .'.mp4', 'azure' ); return response()->json([ 'success' => "Success", 'path_azure' => $path ]); }
后端逻辑:接收前端提交的Blob文件,调用storeAs方法直接上传至Azure存储。
错误指向代码
错误触发于vendor/guzzlehttp/psr7/src/Stream.php文件第228行的read方法:
public function read($length) { if (!isset($this->stream)) { throw new \RuntimeException('Stream is detached'); } if (!$this->readable) { throw new \RuntimeException('Cannot read from non-readable stream'); } if ($length < 0) { throw new \RuntimeException('Length parameter cannot be negative'); } if (0 === $length) { return ''; } $string = fread($this->stream, $length); if (false === $string) { throw new \RuntimeException('Unable to read from stream'); } return $string; }
问题解决方法
1. 修复前端Blob格式与FormData提交
Safari对MIME类型的格式敏感,且提交Blob时需显式指定文件名,避免后端误判资源类型:
// 修改Blob创建时的MIME类型,移除末尾分号 let blob = new Blob(chunks, { type: 'video/mp4' }); // 提交FormData时指定文件名 formData.append('blob', blob, 'recorded_video.mp4');
2. 后端增加文件有效性校验
在处理上传前先校验文件是否合法,避免处理非法资源:
public function store(Request $request) { // 校验上传文件是否存在且有效 if (!$request->hasFile('blob') || !$request->file('blob')->isValid()) { return response()->json(['error' => '无效的上传文件'], 400); } $path = $request->file('blob')->storeAs( 'test_capture', Str::random(16) .'.mp4', 'azure' ); return response()->json([ 'success' => "Success", 'path_azure' => $path ]); }
3. 手动处理Azure文件上传(备选)
若storeAs方法仍存在兼容问题,可尝试用Azure SDK手动上传文件流:
use Illuminate\Support\Facades\Storage; public function store(Request $request) { if (!$request->hasFile('blob') || !$request->file('blob')->isValid()) { return response()->json(['error' => '无效的上传文件'], 400); } $file = $request->file('blob'); $client = Storage::disk('azure')->getAdapter()->getClient(); $containerName = 'your-container-name'; // 替换为你的Azure存储容器名 $blobName = 'test_capture/' . Str::random(16) . '.mp4'; $client->putBlob( $containerName, $blobName, fopen($file->getRealPath(), 'r') ); return response()->json([ 'success' => "Success", 'path_azure' => $blobName ]); }
内容的提问来源于stack exchange,提问作者shadow_blade
相关产品推荐
相关产品推荐

