Agora.io 与 Angular Universal SSR 存在问题
2020-06-02
730
我正在尝试使用 Agora.io 在我的 Angular 9 项目中实现一对一视频通话。当我使用“ng serve”命令运行项目时,它工作正常。但是当我为我的项目构建 SSR 版本(使用 npm run build:ssr)并使用节点在服务器中运行时,我收到以下错误:
(function (exports, require, module, __filename, __dirname) { !function(e,a){for(var i in a)e[i]=a[i]}(exports,function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={i:moduleId,l:!1,exports:{}};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.l=!0,module.exports}return __webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.d=function(exports,name,getter){__webpack_require__.o(exports,name)||Object.defineProperty(exports,name,{enumerable:!0,get:getter})},__webpack_require__.r=function(exports){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(exports,"__esModule",{value:!0})},__webpack_require__.t=function(value,mode){if(1&mode&&(value=__webpack_require__(
ReferenceError: window is not defined
at Object.a1+y (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:1956715)
at __webpack_require__ (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:357)
at Object.U43L (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:1887006)
at __webpack_require__ (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:357)
at Object.Ouvt (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:1659017)
at __webpack_require__ (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:357)
at Object.ZAI4 (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:1950751)
at __webpack_require__ (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:357)
at Object.24aS (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:685847)
at __webpack_require__ (/home/ksk/aiva-ssr/dist/aiva-frontend/server/main.js:1:357)
编辑:
video-call.component.ts 代码
import {Component, Inject, OnInit, PLATFORM_ID} from '@angular/core';
import {AgoraClient, ClientEvent, NgxAgoraService, Stream, StreamEvent} from 'ngx-agora';
import {isPlatformBrowser} from '@angular/common';
@Component({
selector: 'app-video-call',
templateUrl: './video-call.component.html',
styleUrls: ['./video-call.component.css']
})
export class VideoCallComponent implements OnInit {
title = 'video-call';
localCallId = 'agora_local';
remoteCalls: string[] = [];
private client: AgoraClient;
private localStream: Stream;
private uid: number;
isBrowser: boolean;
constructor(private ngxAgoraService: NgxAgoraService,
@Inject(PLATFORM_ID) platformId: object) {
this.uid = Math.floor(Math.random() * 100);
this.isBrowser = isPlatformBrowser(platformId);
}
ngOnInit(): void {
if (this.isBrowser) {
this.client = this.ngxAgoraService.createClient({mode: 'rtc', codec: 'h264'});
this.assignClientHandlers();
// Added in this step to initialize the local A/V stream
this.localStream = this.ngxAgoraService.createStream({streamID: this.uid, audio: true, video: true, screen: false});
this.assignLocalStreamHandlers();
// this.initLocalStream();
this.initLocalStream(() => this.join(uid => this.publish(), error => console.error(error)));
}
}
private assignClientHandlers(): void {
this.client.on(ClientEvent.LocalStreamPublished, evt => {
console.log('Publish local stream successfully');
});
this.client.on(ClientEvent.Error, error => {
console.log('Got error msg:', error.reason);
if (error.reason === 'DYNAMIC_KEY_TIMEOUT') {
this.client.renewChannelKey(
'',
() => console.log('Renewed the channel key successfully.'),
renewError => console.error('Renew channel key failed: ', renewError)
);
}
});
this.client.on(ClientEvent.RemoteStreamAdded, evt => {
const stream = evt.stream as Stream;
this.client.subscribe(stream, {audio: true, video: true}, err => {
console.log('Subscribe stream failed', err);
});
});
this.client.on(ClientEvent.RemoteStreamSubscribed, evt => {
const stream = evt.stream as Stream;
const id = this.getRemoteId(stream);
if (!this.remoteCalls.length) {
this.remoteCalls.push(id);
setTimeout(() => stream.play(id), 1000);
}
});
this.client.on(ClientEvent.RemoteStreamRemoved, evt => {
const stream = evt.stream as Stream;
if (stream) {
stream.stop();
this.remoteCalls = [];
console.log(`Remote stream is removed ${stream.getId()}`);
}
});
this.client.on(ClientEvent.PeerLeave, evt => {
const stream = evt.stream as Stream;
if (stream) {
stream.stop();
this.remoteCalls = this.remoteCalls.filter(call => call !== `${this.getRemoteId(stream)}`);
console.log(`${evt.uid} left from this channel`);
}
});
}
private getRemoteId(stream: Stream): string {
return `agora_remote-${stream.getId()}`;
}
private assignLocalStreamHandlers(): void {
this.localStream.on(StreamEvent.MediaAccessAllowed, () => {
console.log('accessAllowed');
});
// The user has denied access to the camera and mic.
this.localStream.on(StreamEvent.MediaAccessDenied, () => {
console.log('accessDenied');
});
}
private initLocalStream(onSuccess?: () => any): void {
this.localStream.init(
() => {
// The user has granted access to the camera and mic.
this.localStream.play(this.localCallId);
if (onSuccess) {
onSuccess();
}
},
err => console.error('getUserMedia failed', err)
);
}
/**
* Attempts to connect to an online chat room where users can host and receive A/V streams.
*/
join(onSuccess?: (uid: number | string) => void, onFailure?: (error: Error) => void): void {
this.client.join(null, 'foo-bar', this.uid, onSuccess, onFailure);
}
/**
* Attempts to upload the created local A/V stream to a joined chat room.
*/
publish(): void {
this.client.publish(this.localStream, err => console.log('Publish local stream error: ' + err));
}
}
运行 npm run dev:ssr 时的错误日志
Compiled successfully.
/Users/ksk235/Development/AIVA/avia-frontend/dist/aiva-frontend/server/main.js:116761
!function(e,t){ true?module.exports=t():undefined}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var a=t[i]={i:i,l:!1,exports:{}};return e[i].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(i,a,function(t){return e[t]}.bind(null,a));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=36)}([function(e,t,n){"use strict";n.r(t);var i=n(9),a=n.n(i),r=n(10),o=n(3),s=n(2),c=0,d="free",u=[],l=[],f=0;setInterval(function(){Object(o.getParameter)("UPLOAD_LOG")&&p.info("console log upload")},9e5);var p=function(){var e,t,n,i,p,m,g="https://".concat(Object(o.getParameter)("LOG_UPLOAD_SERVER"),"/upload/v1"),v=["DEBUG","INFO","WARNING","ERROR","NONE"],S=0,h=function e(t){d="uploading",setTimeout(function(){!function(e,t,n){var i;Array.isArray(e)||(e=[e]),e=e.map(function(e){return{log_item_id:c++,log_level:e.log_level,payload_str:e.payload}}),i={sdk_version:o.VERSION,process_id:Object(s.a)(),payload:JSON.stringify(e)};try{Object(r.post)(g,i,function(e){"OK"===e?t&&t(e):n&&n(e)},function(e){n&&n(e)},{withCredentials:!0})}catch(e){n&&n(e)}}(t,function(){f=0,0!==u.length?(l=u.length<10?u.splice(0,u.length):u.splice(0,10),e(l)):d="free"},function(){setTimeout(function(){e(l)},f++<2?200:1e4)})},3e3)};t=function(){for(var t=[0],n=0;n<arguments.length;n++)t.push(arguments[n]);e.apply(this,t)},n=function(){for(var t=[1],n=0;n<arguments.length;n++)t.push(arguments[n]);e.apply(this,t)},i=function(){for(var t=[2],n=0;n<arguments.length;n++)t.push(arguments[n]);e.apply(this,t)},p=function(){for(var t=[3],n=0;n<arguments.length;n++)t.push(arguments[n]);e.apply(this,t)};var _={};return m=function(e){_[e]||(i.apply(void 0,arguments),_[e]=!0)},{DEBUG:0,INFO:1,WARNING:2,ERROR:3,NONE:4,enableLogUpload:function(){Object(o.setParameter)("UPLOAD_LOG",!0)},disableLogUpload:function(){Object(o.setParameter)("UPLOAD_LOG",!1)},setProxyServer:function(e){g=e?"https://".concat(e,"/ls/?h=").concat(Object(o.getParameter)("LOG_UPLOAD_SERVER"),"&p=443&d=upload/v1"):"https://".concat(Object(o.getParameter)("LOG_UPLOAD_SERVER"),"/upload/v1")},setLogLevel:function(e){e>4?e=4:e<0&&(e=0),S=e},log:e=function(){var e,t=arguments[0],n=arguments;if(n[0]=(e=new Date).toTimeString().split(" ")[0]+":"+e.getMilliseconds()+" Agora-SDK ["+(v[t]||"DEFAULT")+"]:",function(e,t){if(Object(o.getParameter)("UPLOAD_LOG"))try{t=Array.prototype.slice.call(t);var n="";t.forEach(function(e){"object"===a()(e)&&(e=JSON.stringify(e)),n=n+e+" "}),u.push({payload:n,log_level:e}),"free"===d&&(l=u.length<10?u.splice(0,u.length):u.splice(0,10),h(l))}catch(e){}}(t,n),!(t<S))switch(t){case 0:case 1:console.log.apply(console,n);break;case 2:console.warn.apply(console,n);break;case 3:console.error.apply(console,n);break;default:return void console.log.apply(console,n)}},debug:t,info:n,warning:i,deprecate:m,error:p}}();t.default=p},function(e,t,n){"use strict";n.r(t),n.d(t,"checkValidObject",function(){return o}),n.d(t,"checkValidString",function(){return s}),n.d(t,"checkValidNumber",function(){return c}),n.d(t,"checkValidFloatNumber",function(){return d}),n.d(t,"checkValidBoolean",function(){return u}),n.d(t,"checkValidEnum",function(){return r}),n.d(t,"isValidString",function(){return l}),n.d(t,"isValidNumber",function(){return f}),n.d(t,"isValidBoolean",function(){return m}),n.d(t,"isASCII",function(){return S}),n.d(t,"isInteger",function(){return h}),n.d(t,"isNumber",function(){return _}),n.d(t,"isString",function(){return E}),n.d(t,"isArray",function(){return I}),n.d(t,"isEmpty",function(){return T}),n.d(t,"isValidToken",function(){return g}),n.d(t,"isValidChannelName",function(){return v});var i=n(9),a=n.n(i),r=function(e,t,n){for(var i=0;i<n.length;i++)if(e===n[i])return!0;throw new Error("".concat(t," can only be set as ").concat(JSON.stringify(n)))},o=function(e,t){if(!e)throw new Error("Invalid param: ".concat(t||"param"," cannot be empty"));if("object"!==a()(e))throw new Error("".concat(t||"This paramter"," is of the object type"));return!0},s=function(e,t,n,i,a){if(T(n)&&(n=1),i=i||255,T(a)&&(a=!0),T(e))throw new Error("".concat(t||"param"," cannot be empty"));if(!l(e,n,i,a))throw new Error("Invalid ".concat(t||"string param",": Length of the string: [").concat(n,",").concat(i,"].").concat(a?" ASCII characters only.":""))},c=function(e,t,n,i){if(T(n)&&(n=1),i=i||1e4,T(e))throw new Error("".concat(t||"param"," cannot be empty"));if(!f(e,n,i))throw new Error("Invalid ".concat(t||"number param",": The value range is [").concat(n,",").concat(i,"]. integer only"))},d=function(e,t,n,i){if(null==e)throw new Error("".concat(t||"param"," cannot be null"));if(T(n)&&(n=0),i=i||1e4,T(e))throw new Error("".concat(t||"param"," cannot be empty"));if(!p(e,n,i))throw new Error("Invalid ".concat(t||"number param",": The value range is [").concat(n,",").concat(i,"]."))},u=function(e,t){if(T(e))throw new Error("".concat(t||"param"," cannot be empty"));if(!m(e))throw new Error("Invalid ".concat(t||"boolean param",": The value is of the boolean type."))},l=function(e,t,n,i){return t||(t=0),n||(n=Number.MAX_SAFE_INTEGER),T(i)&&(i=!0),E(e)&&(!i||S(e))&&e.length>=t&&e.length<=n},f=function(e,t,n){return h(e)&&e>=t&&e<=n},p=function(e,t,n){return _(e)&&e>=t&&e<=n},m=function(e){return"boolean"==typeof e},g=function(e){return l(e,1,2047)},v=function(e){return E(e)&&/^[a-zA-Z0-9 \!\#\$\%\&\(\)\+\-\:\;\<\=\.\>\?\@\[\]\^\_\{\}\|\~\,]{1,64}$/.test(e)},S=function(e){if("string"==typeof e){for(var t=0;t<e.length;t++){var n=e.charCodeAt(t);if(n<0||n>255)return!1}return!0}},h=function(e){return"number"==typeof e&&e%1==0},_=function(e){return"number"==typeof e},E=function(e){return"string"==typeof e},I=function(e){return e instanceof Array},T=function(e){return null==e}},function(e,t,n){"use strict";var i=n(14),a=n.n(i),r=n(6),o=n.n(r),s=n(3),c=n(0),d=n(10),u=n(16),l=n.n(u);n.d(t,"b",function(){return g}),n.d(t,"a",function(){return m});var f={eventType:null,sid:null,lts:null,success:null,cname:null,uid:null,peer:null,cid:null,elapse:null,extend:null,vid:0},p=null,m=function(){return p||(p="process-"+l()(),c.default.info("processId: "+p)),p},g=function(){var e={list:{}};e.url=Object(d.shouldUseHttps)()?"https://".concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),":6443/events/message"):"http://".concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),":6080/events/message"),e.urlBackup=Object(d.shouldUseHttps)()?"https://".concat(Object(s.getParameter)("EVENT_REPORT_BACKUP_DOMAIN"),":6443/events/message"):"http://".concat(Object(s.getParameter)("EVENT_REPORT_BACKUP_DOMAIN"),":6080/events/message"),e.setProxyServer=function(t){t?(e.url=Object(d.shouldUseHttps)()?"https://".concat(t,"/rs/?h=").concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),"&p=6443&d=events/message"):"http://".concat(t,"/rs/?h=").concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),"&p=6080&d=events/message"),e.urlBackup=Object(d.shouldUseHttps)()?"https://".concat(t,"/rs/?h=").concat(Object(s.getParameter)("EVENT_REPORT_BACKUP_DOMAIN"),"&p=6443&d=events/message"):"http://".concat(t,"/rs/?h=").concat(Object(s.getParameter)("EVENT_REPORT_BACKUP_DOMAIN"),"&p=6080&d=events/message"),c.default.debug("reportProxyServerURL: ".concat(e.url)),c.default.debug("reportProxyServerBackupURL: ".concat(e.urlBackup))):(e.url=Object(d.shouldUseHttps)()?"https://".concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),":6443/events/message"):"http://".concat(Object(s.getParameter)("EVENT_REPORT_DOMAIN"),":6080/event
A server error has occurred.
node exited with 1 code.
connect ECONNREFUSED 127.0.0.1:63303
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev:ssr: `ng run aiva-frontend:serve-ssr`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev:ssr script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/ksk235/.npm/_logs/2020-06-08T19_38_05_006Z-debug.log
2个回答
请检查您是否在服务器端代码中使用了
window
关键字。如果使用了,请不要使用它。在服务器端代码中使用
window
关键字通常会导致此错误。
Shriya Ramakrishnan
2020-06-05
使用 SSR 时,无法访问浏览器对象(
document
、
navigator
、'window` 等)。
您可以使用
isPlatformBrowser
检查包装尝试访问这些变量的代码,以便仅在浏览器上执行它。
import {isPlatformBrowser} from "@angular/common";
//...
constructor(@Inject(PLATFORM_ID) private platformId: Object)
{
if(isPlatformBrowser(this.platformId))
{
//access window/document...
}
else { /*server side .. don't access window*/ }
}
如果不能,您可以尝试将
domino
添加到您的
server.ts
const domino = require('domino');
const win = domino.createWindow('/path/to/your/project/dist/client/index.html');
global['window'] = win;
global['document'] = win.document;
global['navigator'] = win.navigator;
David
2020-06-06