2757com 2

Action 2757com发出以后,进行项目打包的时候

HTML5 录音的踩坑之旅

2017/12/25 · HTML5 ·
录音

原文出处:
翁旺   

1、axios安装

1.1、 利用npm安装npm install axios –save

1.2、 利用bower安装bower install axios –save

1.3、 直接利用cdn引入<script
src=”;

2757com 1

图1

初探 Headless Chrome

2017/06/15 · 基础技术 ·
Chrome

原文出处: 饿了么前端   

原文出处:
阮一峰   

开篇闲扯

前一段时间的一个案子是开发一个有声课件,大致就是通过导入文档、图片等资源后,页面变为类似
PPT
的布局,然后选中一张图片,可以插入音频,有单页编辑和全局编辑两种模式。其中音频的导入方式有两种,一种是从资源库中导入,还有一种就是要提到的录音。
说实话,一开始都没接触过 HTML5 的 Audio
API,而且要基于在我们接手前的代码中进行优化。当然其中也踩了不少坑,这次也会围绕这几个坑来说说感受(会省略一些基本对象的初始化和获取,因为这些内容不是这次的重点,有兴趣的同学可以自行查找
MDN 上的文档):

  • 调用 Audio API 的兼容性写法
  • 获取录音声音的大小(应该是频率)
  • 暂停录音的兼容性写法
  • 获取当前录音时间

 

2、配置访问路径

 在项目开发的时候,接口联调的时候一般都是同域名下,且不存在跨域的情况下进行接口联调,但是当我们现在使用vue-cli进行项目打包的时候,我们在本地启动服务器后,比如本地开发服务下是
这样的访问页面,但是我们的接口地址是

这样的接口地址,我们这样直接使用会存在跨域的请求,导致接口请求不成功,因此我们需要在打包的时候配置一下,我们进入
config/index.js 代码下如下配置即可:

2757com 2

图2


什么是 Headless Chrome

Headless Chrome 是 Chrome
浏览器的无界面形态,可以在不打开浏览器的前提下,使用所有 Chrome
支持的特性运行你的程序。相比于现代浏览器,Headless Chrome 更加方便测试
web 应用,获得网站的截图,做爬虫抓取信息等。相比于出道较早的
PhantomJS,SlimerJS 等,Headless Chrome 则更加贴近浏览器环境。

上一篇文章,我介绍了 Redux 的基本做法:用户发出 Action,Reducer
函数算出新的 State,View 重新渲染。

录音前的准备

开始录音前,要先获取当前设备是否支持 Audio API。早期的方法
navigator.getUserMedia 已经被 navigator.mediaDevices.getUserMedia
所代替。正常来说现在大部分的现代浏览器都已经支持navigator.mediaDevices.getUserMedia
的用法了,当然MDN上也给出了兼容性的写法

JavaScript

const promisifiedOldGUM = function(constraints) { // First get ahold of
getUserMedia, if present const getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // Some
browsers just don’t implement it – return a rejected promise with an
error // to keep a consistent interface if (!getUserMedia) { return
Promise.reject( new Error(‘getUserMedia is not implemented in this
browser’) ); } // Otherwise, wrap the call to the old
navigator.getUserMedia with a Promise return new
Promise(function(resolve, reject) { getUserMedia.call(navigator,
constraints, resolve, reject); }); }; // Older browsers might not
implement mediaDevices at all, so we set an empty object first if
(navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; }
// Some browsers partially implement mediaDevices. We can’t just assign
an object // with getUserMedia as it would overwrite existing
properties. // Here, we will just add the getUserMedia property if it’s
missing. if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = promisifiedOldGUM; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const promisifiedOldGUM = function(constraints) {
// First get ahold of getUserMedia, if present
const getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
 
// Some browsers just don’t implement it – return a rejected promise with an error
// to keep a consistent interface
if (!getUserMedia) {
return Promise.reject(
new Error(‘getUserMedia is not implemented in this browser’)
);
}
 
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
 
// Older browsers might not implement mediaDevices at all, so we set an empty object first
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
 
// Some browsers partially implement mediaDevices. We can’t just assign an object
// with getUserMedia as it would overwrite existing properties.
// Here, we will just add the getUserMedia property if it’s missing.
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = promisifiedOldGUM;
}

因为这个方法是异步的,所以我们可以对无法兼容的设备进行友好的提示

JavaScript

navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) { // 成功 }, function(error) { // 失败 const {
name } = error; let errorMessage; switch (name) { // 用户拒绝 case
‘NotAllowedError’: case ‘PermissionDeniedError’: errorMessage =
‘用户已禁止网页调用录音设备’; break; // 没接入录音设备 case
‘NotFoundError’: case ‘DevicesNotFoundError’: errorMessage =
‘录音设备未找到’; break; // 其它错误 case ‘NotSupportedError’:
errorMessage = ‘不支持录音功能’; break; default: errorMessage =
‘录音调用错误’; window.console.log(error); } return errorMessage; } );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
navigator.mediaDevices.getUserMedia(constraints).then(
function(mediaStream) {
// 成功
},
function(error) {
// 失败
const { name } = error;
let errorMessage;
switch (name) {
// 用户拒绝
case ‘NotAllowedError’:
case ‘PermissionDeniedError’:
errorMessage = ‘用户已禁止网页调用录音设备’;
break;
// 没接入录音设备
case ‘NotFoundError’:
case ‘DevicesNotFoundError’:
errorMessage = ‘录音设备未找到’;
break;
// 其它错误
case ‘NotSupportedError’:
errorMessage = ‘不支持录音功能’;
break;
default:
errorMessage = ‘录音调用错误’;
window.console.log(error);
}
return errorMessage;
}
);

一切顺利的话,我们就可以进入下一步了。
(这里有对获取上下文的方法进行了省略,因为这不是这次的重点)

3、封装axios( 我们进入 axios/api.js   代码下如下配置即可)

import axios from ‘axios’

import { Message, Loading } from ‘element-ui’

let loadingInstance

const CancelToken = axios.CancelToken

// request拦截器

axios.interceptors.request.use(

  config => {

    console.log(‘请求开始’)

    // 全屏Loading开始

    loadingInstance = Loading.service({ fullscreen: true })

    return config

  },

  error => {

    // Do something with request error

    console.log(error) // for debug

    Promise.reject(error)

  }

)

// respone拦截器

axios.interceptors.response.use(

  response => {

    if (

      typeof response.data === ‘string’ &&

      response.data.indexOf(‘xmlns’) > -1

    ) {

      response.status = 302

    }

    // Loading关闭

    loadingInstance.close()

    switch (response.status) {

      case 302:

        // 可能登录超时

        store.state.app.storeSession = true

        console.log(‘ccc’)

        // window.location.href = window.location.origin + ‘/logout’

        break

      case 401:

        // 可能登录超时

        window.location.href = window.location.origin + ‘/logout’

        break

      case 404:

        // 404

        window.location.href = ‘../views/pages/error404.vue’

        break

      case 500:

        // 502

        window.location.href = ‘../views/pages/500.vue’

        break

      case 502:

        // 502

        window.location.href = ‘../views/pages/error.vue’

        break

    }

    const res = response.data

    // 系统级错误

    if (res.status === 500) {

      Message({

        message: ‘服务器出错啦~:’ + res.res.codeMsg,

        type: ‘error’,

        duration: 5 * 1000

      })

      return Promise.reject(res.res.codeMsg)

    } else if (typeof res.status !== ‘undefined’ && res.status !==
200) {

      console.log(‘系统运行错误:’, res)

      Message({

        message: ‘系统运行错误:’ + res.statusMsg,

        type: ‘error’,

        duration: 5 * 1000

      })

      return Promise.reject(res.statusMsg)

    } else if (

      typeof res.res !== ‘undefined’ &&

      typeof res.res.code !== ‘undefined’ &&

      res.res.code !== 1000

    ) {

      Message({

        message: ‘业务处理错误:’ + res.res.codeMsg.client_error,

        type: ‘error’,

        duration: 5 * 1000

      })

      return Promise.reject(res.res.codeMsg)

      // 业务处理

    } else {

      // console.log(response.data)

      // 处理 lang

      if (typeof res.res === ‘undefined’) {

        // 传送2进制文件

        res.blob = res

        res.filename = decodeURI(

          response.headers[‘content-disposition’].split(‘=’)[1]

        )

        return res

      } else {

        return res.res.data

      }

    }

  },

  error => {

    // Loading关闭

    loadingInstance.close()

    if (error.message !== ‘USERCANCEL’) {

      Message({

        message: ‘数据请求超时!!’,

        type: ‘error’,

        duration: 5 * 1000

      })

    }

    return Promise.reject(error)

  }

)

// 自定义 处理 返回信息

export function custom(config) {

  const params = {}

  const d = new Date()

  params.time = d.toISOString()

  params.lang = navigator.language || navigator.browserLanguage

  params.req = {}

  params.req.source = ‘pc’

  params.req.data = config.params

  return axios({

    method: config.method,

    url: config.url,

    data: params,

    responseType: ‘arraybuffer’,

    baseURL: ‘/be/’, // api的base_url  //需要修改的

    timeout: 30000,

    headers: {

      accept: ‘application/json’

    }

  })

}

// 统一请教模版

export function fetch(config) {

  if (typeof config.cancelToken === ‘undefined’) {

    config.cancelToken = new CancelToken(function (cancel) {

      console.log(‘取消’)

    })

  }

  const params = {}

  const d = new Date()

  params.time = d.toISOString()

  params.lang = navigator.language || navigator.browserLanguage

  params.req = {}

  params.req.source = ‘pc’

  params.req.data = config.params

  return axios({

    method: config.method,

    url: config.url,

    data: params,

    baseURL: ‘/be/’, // api的base_url  //需要修改的

    timeout: config.timeout ? config.timeout : 30000,

    headers: {

      accept: ‘application/json’

    },

    cancelToken: config.cancelToken

  })

}


如何获取 Headless Chrome

目前,Mac 上 Chrome 59
beta 版本与
Linux 上的 Chrome 57+ 已经开始支持 headless 特性。Windows 上 Chrome
暂时不支持,可以使用 Chrome Canary
60 进行开发。

2757com 3

发表评论

电子邮件地址不会被公开。 必填项已用*标注