Agora.io与Angular通用SSR的问题

问题描述 投票:0回答:2

我试图在我的Angular 9项目中使用Agora.io实现一对一的视频调用。当我使用 "ng serve "命令运行项目时,它工作正常。但是当我为我的项目构建SSR时(使用npm run build:ssr),并在服务器上使用node运行时,我得到了以下错误。

(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 codes

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运行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
angular angular-universal agora.io
2个回答
0
投票

请检查你是否使用了 "Agora.io "命令。window 关键字在你的服务器端代码中。如果你有,请不要使用它。在服务器端代码中使用 window 服务器端代码中的关键字通常会引起这个错误。


0
投票

浏览器对象 (document, navigator, 'window`,...)在使用SSR时无法访问。

你可以在试图访问这些变量的代码中使用 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;

0
投票

你有两种方法来处理这个问题。

  1. 注入 PLATFORM_ID 作为你所需组件中的一个服务,然后将你的有问题的代码包装在一个条件中,如下所示。


    import { isPlatformBrowser, isPlatformServer } from '@angular/common';
    import {Inject, OnInit, PLATFORM_ID} from '@angular/core';

    constructor (@Inject(PLATFORM_ID) private platformId: any) {}

    ngOnInit() {
        this.prepareCkeditor5();
    }

    prepareCkeditor5() {
        if (isPlatformBrowser(this.platformId)) {
            // Client mode detected
        } else if (isPlatformServer(this.platformId)){
            //  server mode detected
        }
    }

  1. 使用 骨牌 自动完成
© www.soinside.com 2019 - 2024. All rights reserved.