当前位置: 首页 > news >正文

福州 网站建设 快搜网络网站用excel做数据库

福州 网站建设 快搜网络,网站用excel做数据库,wordpress新闻站主题,做网站是怎么赚钱的违法起因 事情的起因是调试 IOS 手机下播放服务器接口返回的 mp4 文件流失败。对于没调试过移动端和 Safari 的我来说着实费了些功夫#xff0c;网上和AI也没有讲明白。好在最终大概理清楚了#xff0c;在这里整理出来供有缘人参考。 问题 因为直接用 IOS 手机的浏览器打开页面…起因 事情的起因是调试 IOS 手机下播放服务器接口返回的 mp4 文件流失败。对于没调试过移动端和 Safari 的我来说着实费了些功夫网上和AI也没有讲明白。好在最终大概理清楚了在这里整理出来供有缘人参考。 问题 因为直接用 IOS 手机的浏览器打开页面去播放也能复现所以问题出现在 IOS上的 Safari 浏览器上。 问题主要分两类 一、视频能播放但是不主动设置 poster就不显示默认的 poster二、视频不能播放 首先文件是没有问题的是主流浏览器都支持的视频编码格式为 H.264(AVC) 的 .mp4 文件由文件格式导致的播放失败问题网上很多这里就不赘述了。 问题复现和解决 因为其他浏览器可以正常播放所以用来对比差异时我直接在PC端Edge查看信息而 Safari 是在手机上访问项目页面以及局域网下访问本地运行的 web 服务页面。 用到的工具如下 Live Server 用来运行本地 web 页面node nodemon Express 用来运行文件服务模拟后端接口nodemon 方便实时同步运行修改内容video.js 播放视频的插件直接用 CDN。vConsole 移动端查看控制台直接用 CDN 编写简单 demo 排查问题的时候我是一点一点将实现方式还原到最原始的方式 后端接口 video.js后端接口 video标签本地运行的接口 video标签本地文件 video标签 所以这里再梳理就可以反向从最简单的方式排查在本地写个用本地视频文件 video标签的demo为了后续排查方便将事件日志也打印出来。 视频资源我用的 https://vjs.zencdn.net/v/oceans.mp4 下载到本地不过它的开头是黑屏淡入的为了方便区分 “不显示poster”我将开头的几秒黑屏裁剪掉了。 也可以用安卓手机录制一个默认就是支持播放的 mp4 文件。PS别用QQ录屏编码不对 !DOCTYPE html html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /script srchttps://unpkg.com/vconsolelatest/dist/vconsole.min.js/scriptscriptvar vConsole new window.VConsole()/scriptstyle#video {width: 480px;height: 25vh;max-width: 100%;/* 背景色用于在视频不显示poster时查看占位 */background: pink;border: 4px solid pink;}/style/headbodydiv classvideo-boxvideo idvideo srcoceans.mp4 controls preloadauto playsinlinetrue muted/video/divdiv idlogh2日志方便手机上的 Safari 查看/h2div classlog__content/div/divscript// 打印日志function log(msg) {// 页面上打印日志const logContentEl document.querySelector(.log__content)const pEl document.createElement(p)pEl.textContent msglogContentEl.appendChild(pEl)// 控制台打印日志console.log(msg)}const video document.getElementById(video)// 主要关心的事件const eventNames [{ name: abort, desc: 当音频/视频的加载已放弃时触发 },{ name: canplay, desc: 当浏览器可以开始播放音频/视频时触发 },{ name: canplaythrough, desc: 当浏览器预计能够在不因缓冲而停顿的情况下持续播放指定的音频/视频时触发 },{ name: durationchange, desc: 当音频/视频的时长已更改时触发 },{ name: error, desc: 当在音频/视频加载期间发生错误时触发 },{ name: loadeddata, desc: 当浏览器已加载音频/视频的当前帧时触发 },{ name: loadedmetadata, desc: 当浏览器已加载音频/视频的元数据时触发 },{ name: loadstart, desc: 当浏览器开始查找音频/视频时触发 },{ name: play, desc: 当音频/视频已开始或不再暂停时触发 },{ name: playing, desc: 当音频/视频在因缓冲而暂停或停止后已就绪时触发 },{ name: progress, desc: 当浏览器正在下载音频/视频时触发 },{ name: timeupdate, desc: 当音频/视频的播放位置发生改变时触发 },{ name: waiting, desc: 当视频由于需要缓冲下一帧而停止等待时触发 }]// 注册video事件监听器eventNames.forEach(v {video.addEventListener(v.name, () {// 打印日志log(【readyState: ${video.readyState}】 ${v.name}: ${v.desc})})})/script/body /html preload 默认是 metadata和 auto 的日志结果一样。为了排除一些可能性我将其设置了 auto。 playsinlinetrue 防止 IOS 播放视频时自动打开全屏。 问题1 不显示预览图 demo 页面加载后发现Safari 浏览器没有显示视频的预览图 Edge 显示了预览图 通过日志发现Safari 加载完元数据后(loadedmetadata)就不会继续加载了。 我们知道视频的预览图就是 video 标签的 poster 属性当 poster 有值时就会显示指定的图片当 poster 没有值时浏览器就会自动处理而不同浏览器的处理方式也不一样可能会有这几种情况 如果配置了预加载显示加载后的第一帧或第二、三桢。什么都不显示或显示默认的播放器背景样式 从日志可以看到Safari 只加载了元数据并没有加载画面。查看官方文档得到了解答 再看 poster 的说明 既然如此那只能提供一个 poster 来解决了。 问题2 视频不能播放 问题复现 播放 demo 示例里的视频是可以正常播放的。 将播放方式改成 video.js 本地文件播放是正常的。代码如下 !DOCTYPE html html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /link hrefhttps://unpkg.com/video.js7.10.2/dist/video-js.min.css relstylesheet /script srchttps://unpkg.com/vconsolelatest/dist/vconsole.min.js/scriptscriptvar vConsole new window.VConsole()/scriptstyle#video {width: 480px;max-width: 100%;height: 25vh;/* 背景色用于在视频不显示poster时查看占位 */background: pink;border: 4px solid pink;}/style/headbodyvideo idvideo classvideo-js controls preloadauto playsinlinetrue mutedsource srcoceans.mp4 typevideo/mp4 //videodiv idlogh3日志方便手机上的 Safari 查看/h3div classlog__content/div/divscript srchttps://unpkg.com/video.js7.10.2/dist/video.min.js/scriptscript// 打印日志function log(msg) {// 页面上打印日志const logContentEl document.querySelector(.log__content)const pEl document.createElement(p)pEl.textContent msglogContentEl.appendChild(pEl)// 控制台打印日志console.log(msg)}// 主要关心的 videojs 事件const eventNames [{ name: abort, desc: 当音频/视频的加载已放弃时触发 },{ name: canplay, desc: 当浏览器可以开始播放音频/视频时触发 },{ name: canplaythrough, desc: 当浏览器预计能够在不因缓冲而停顿的情况下持续播放指定的音频/视频时触发 },{ name: durationchange, desc: 当音频/视频的时长已更改时触发 },{ name: error, desc: 当在音频/视频加载期间发生错误时触发 },{ name: loadeddata, desc: 当浏览器已加载音频/视频的当前帧时触发 },{ name: loadedmetadata, desc: 当浏览器已加载音频/视频的元数据时触发 },{ name: loadstart, desc: 当浏览器开始查找音频/视频时触发 },{ name: play, desc: 当音频/视频已开始或不再暂停时触发 },{ name: playing, desc: 当音频/视频在因缓冲而暂停或停止后已就绪时触发 },{ name: progress, desc: 当浏览器正在下载音频/视频时触发 },{ name: timeupdate, desc: 当音频/视频的播放位置发生改变时触发 },{ name: waiting, desc: 当视频由于需要缓冲下一帧而停止等待时触发 }]const player videojs(video)player.ready(() {// 注册video事件监听器eventNames.forEach(v {player.on(v.name, () {// 打印日志log(【readyState: ${player.readyState()}】 ${v.name}: ${v.desc})})})})/script/body /html 然后换成后端接口地址Edge 可以播放但是 Safari 就失败了。 video 标签方式 video.js 方式报错 The media could not be loaded, either because the server or network failed or because the format is not supported. 我肯定不是服务器网络故障也不是文件格式不支持所以原因只能是接口了。 本地模拟接口 为了不麻烦后端同事我只能在本地搭建一个服务器模拟项目接口。 搭建服务 创建 app.js 文件 const express require(express) const fs require(fs) const path require(path)const app express()app.get(/, (req, res) {res.send(Stupid IOS) })app.listen(3000, () {const ip 192.169.3.7 // 我的局域网ipconsole.log(server is running on http://${ip}:3000) }) # 安装依赖 npm i express # 已安装 nodemon所以直接使用 nodemon app.js访问 http://192.169.3.7:3000/。把 oceans.mp4 视频文件放到 app.js 同目录下后面就编写接口就行。 方式1 使用 express 封装好的方法返回文件流 // 方式1: 使用封装好的方法返回文件流 app.get(/type1/:file, (req, res) {const fileName req.params.fileconst filePath path.join(__dirname, fileName)res.sendFile(filePath) })文件地址http://192.169.3.7:3000/type1/oceans.mp4 video标签和 video.js 播放都正常。 方式2 手动读取全部文件流并返回 同样是接口本地模拟的正常项目接口不能播放那就继续更细致的模拟手动读取文件流设置相同的响应头。 查看项目接口的响应头排除一些范围只模拟有可能影响的 // 方式2: 手动读取全部文件流并返回 app.get(/type2/:file, (req, res) {const fileName req.params.fileconst filePath path.join(__dirname, fileName)// 打印请求头console.log(req.headers)fs.stat(filePath, (err, stats) {if (err) {return res.status(404).send(file not found)}// 设置响应头res.set({Accept-Ranges: bytes, // 支持 Range 请求Cache-Control: no-cache, no-store, // 不缓存Content-Type: video/mp4;charsetUTF-8,Content-Range: bytes 0-${stats.size - 1}/${stats.size},Content-Length: stats.size,Content-Disposition: attachment;filenameoceans.mp4,ETag: ${stats.ino.toString()}-${stats.size.toString()}-${Date.now().toString()},Last-Modified: stats.mtime.toUTCString(),Pragma: no-cache})const stream fs.createReadStream(filePath)stream.pipe(res)}) })文件地址http://192.169.3.7:3000/type2/oceans.mp4 问题依旧存在于是查看官方文档找到一段说明 Range 请求就是范围请求或分块传输客户端通过请求头 Range 指定当前请求想要获取的数据子节范围服务器根据这个范围读取文件流并将读取的内容返回给客户端。 通常服务器会返回 206 状态码表示范围请求的响应结果。并且需要在响应头中包含 Content-Range 字段指明实际返回的数据范围以及整个资源的总大小。 可是我加了支持 range 请求的响应头啊Accept-Ranges: bytes。 继续看文档下面介绍了如何确认服务器是否支持 range 请求 大概意思就是主动发送一个指定范围 100 bytes 的请求看返回的数据是100 bytes那就是支持如果返回了整个文件那就是不支持。 查看之前服务器中打印的请求头Range 请求头的值 Edge 是 0-表示获取整个资源Safari 是 0-1表示获取位置0 和 1 的子节的资源注意可不是从开头到第1个子节这个范围的请求数是2个子节。 因为我每次都返回的完整的文件流没有按照 Safari 的要求范围处理所以属于不支持。 看来仅仅配置响应头是不行的还要正确处理请求头中的指定范围。 方式3 手动读取指定范围的文件流并返回-分块传输 原来 Safari 会先发送一个获取范围为 bytes0-1 的请求以测试服务器是否支持 range 请求。 于是我手动改了下响应头去掉那些没有影响的还是返回整个文件流 // 设置响应头res.set({Accept-Ranges: bytes, // 支持 Range 请求Cache-Control: no-cache, no-store, // 不缓存Content-Type: video/mp4;charsetUTF-8,Content-Range: bytes 0-1/${stats.size},Content-Length: stats.size,})看来仅仅伪造响应头还是不行还要返回正确大小的文件流那就编写分块传输的接口 // 方式3: 手动读取指定范围的文件流并返回-分块传输 app.get(/type3/:file, (req, res) {const fileName req.params.fileconst filePath path.join(__dirname, fileName)// 查看请求头的范围console.log(req.headers.range)fs.stat(filePath, (err, stats) {if (err) {return res.status(404).send(file not found)}// 设置响应头res.set({Accept-Ranges: bytes, // 支持 Range 请求Cache-Control: no-cache, no-store, // 不缓存Content-Type: video/mp4})const range req.headers.rangelet partslet start 0let end stats.size - 1if (range) {parts range.replace(/bytes/, ).split(-)start parseInt(parts[0], 10)end parts[1] ? parseInt(parts[1], 10) : stats.size - 1}if (start stats.size || end stats.size) {// 如果Range请求超出文件大小返回416状态码return res.status(416).end()}if (start 0 end 0) {// 处理 Range 请求res.set({Content-Range: bytes ${start}-${end}/${stats.size},Content-Length: end - start 1})// 部分内容状态码返回200浏览器也能正常处理res.status(206)}const stream fs.createReadStream(filePath, { start, end })stream.pipe(res)}) })终于视频可以正常播放了video.js 也可以播放。 Safari 的校验还挺严格如果服务器正确处理了这个2子节的请求Safari 就会开始正式发送正常范围的请求。 服务器的日志可以体现出来 bytes0-1 bytes0-51883958 bytes196608-51883958 bytes458752-51883958最终查看了后端代码果然接口没有处理 range 请求在修改逻辑后功能终于正常。 继续伪造 range 接口 为了搞清楚 Safari 的校验到底有多严格我再次尝试模拟了一下第一次请求的响应 const range req.headers.rangelet partslet start 0let end stats.size - 1// 增加逻辑 start-----------------------------------------if (range bytes0-1) {// 设置响应头res.set({Accept-Ranges: bytes, // 支持 Range 请求Cache-Control: no-cache, no-store, // 不缓存Content-Type: video/mp4;charsetUTF-8,Content-Range: bytes 3-3/${stats.size}, // 随便写个范围Content-Length: 2})const stream fs.createReadStream(filePath, { start:100, end:200 }) // 随便获取个范围但不能少于2stream.pipe(res)return res.status(206) // 随便返回个状态码}// 增加逻辑 end-----------------------------------------if (range) {parts range.replace(/bytes/, ).split(-)start parseInt(parts[0], 10)end parts[1] ? parseInt(parts[1], 10) : stats.size - 1}再次提醒bytes0-1 表示请求的位置是0 和 1的子节是2个子节而不是 1-01 的子节数量。 不断测试下发现只要满足这几个要求Safari 就认为接口支持 range 请求 Content-Length 要正确。Content-Range 的范围要合理。返回了不少于 Range 请求头要求大小的文件流数据。 而下面这几点不影响 Safari 的校验结果 Content-Range 的范围和 Range 的指定范围不一样读取的数据范围和 Range 的指定范围不一样返回任意状态码 总结 IOS 上的 Safari 不支持 video 预加载(preload)浏览器不会自动提取帧画面作为默认的 poster 预览图Safari 上使用 video 播放视频必须支持并正确处理 Range 范围请求浏览器会先发送 bytes0-1 范围的请求来测试服务器是否支持 Range 请求如果校验成功就会继续发送正常范围的 Range 请求。否则不再请求资源。
http://www.w-s-a.com/news/580418/

相关文章:

  • 电线电缆技术支持中山网站建设广告设计培训学校有哪些
  • 如何禁止通过ip访问网站wordpress无法调用主题布局和图片
  • 江西建设工程信息网站重庆网站推广大全
  • 南浔区住房城乡建设局网站网页设计基础学什么
  • 萧山做网站的企业网站建设 西安
  • 江西省城乡建设厅网站百度站长资源平台
  • 本地搭建linux服务器做网站免费查企业信息查询
  • 电商网站建设与运营网上购物哪个网站最好
  • 做app做网站从何学起网站设计需要什么证
  • 设计网站最重要的是要有良好的短网址还原
  • 大连建设银行招聘网站做seo是要先有网站吗
  • 中山做网站的wordpress建站教程百科
  • 湛江专业网站制作做网站需要工具
  • 做音箱木工网站吉林平安建设网站
  • 品牌网站建设咨询灯光设计网站推荐
  • 温州网站运营打开百度一下网页版
  • 网站有情链接怎么做住房公积金个体工商户
  • 内蒙古网站开发网站开发验收资料
  • 温州网站建设首选国鼎网络网络营销方法可分为两类
  • 做张家界旅游网站多少钱企业推广网络营销
  • 代做毕设网站推荐广东手机微信网站制作
  • 福州建设工程质量监督网站专业做公司宣传网站的
  • 百度云建站教程网站工程师是做什么的
  • 手机在线制作网站一级消防工程师考试试题及答案
  • 网站设计的需求网页制作教程和素材
  • 徐州网站建设 网站推广WordPress 文章编辑
  • 做什么网站比较受欢迎软件商店下载安装2023版本最新
  • 做ip资讯的网站怎么在wordpress中套用同行网页
  • 医院网站如何备案东莞优化公司收费
  • 罗村网站开发适合ps做图的素材网站有哪些