Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/30.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular nguniversal express发动机请求空喷油器_Angular_Express_Server Side Rendering_Angular Universal - Fatal编程技术网

Angular nguniversal express发动机请求空喷油器

Angular nguniversal express发动机请求空喷油器,angular,express,server-side-rendering,angular-universal,Angular,Express,Server Side Rendering,Angular Universal,我正在使用@nguniversal/express engine成功运行angular universal应用程序。我无法工作的部分是在angular应用程序中注入node/expressreq对象。对我来说,遵循这个原则并不能解决问题。错误是 NullInjectorError:InjectionToken请求没有提供程序 在服务器上,我使用以下摘录设置了express引擎 app.engine('html',ngExpressEngine({ bootstrap:AppServerModul

我正在使用
@nguniversal/express engine
成功运行angular universal应用程序。我无法工作的部分是在angular应用程序中注入node/express
req
对象。对我来说,遵循这个原则并不能解决问题。错误是

NullInjectorError:InjectionToken请求没有提供程序

在服务器上,我使用以下摘录设置了express引擎

app.engine('html',ngExpressEngine({
bootstrap:AppServerModuleNgFactory,//给它一个要引导的模块,
提供程序:[provideModuleMap(惰性模块映射)]
}));
app.set('view engine','html');
app.set('views',join(DIST_文件夹,'browser');
app.get('*.',express.static(join(DIST_文件夹,'browser'));
并使用(1)呈现索引文件

app.get('*',(请求:请求,res)=>{
res.render(join(DIST_文件夹,'browser','index.html'),{req});
});
应用程序组件中的注入看起来像

构造函数(
@注入(请求)私有请求:请求
) {}
请求
是从@nguniversal/express engine/tokens导入的。我还测试了在渲染部分(1)中添加以下条目,但它也不起作用

providers: [ { provide: REQUEST, useValue: req } ]
还尝试使用
@Optional()
装饰器注入,并使用
平台ID
检查平台是否为
服务器
,请求对象是否未注入且
为空

您对如何成功访问angular本身的
req
对象有什么建议吗?

您不能在浏览器中访问
REQUEST
,它是从
expressjs
传递到
ng universal
的服务器端对象。因此,在最坏的情况下,您的代码应该执行以下操作

constructor(
  @Inject(PLATFORM_ID) private platformId,
  @Optional() @Inject(REQUEST) private request
) {
    doSomethingWithRequestIfServer();
}

someOtherMethod() {
    doSomethingWithRequestIfServer();
}

doSomethingWithRequestIfServer() {
    if (isPlatformServer(this.platformId)) {
        // should see this in stdout of node process, or wherever node logs
        console.log('rendering server side for request:', req);
        /* use req */
    } else {
        // browser console should print null
        console.log('working browser side, request should be null', req);
    }
}    
然后,在浏览器中,应用程序将不会查看请求,而在服务器端呈现时,应用程序将不会查看请求。也就是说,服务器端渲染将运行angular应用程序一次,因为此渲染的结果HTML将发送到浏览器。然后,浏览器将再次引导Angular应用程序,并从服务器渲染完成的位置拾取

在最好的情况下,为了避免
如果
和平台检查,我建议您对应用程序进行布局,使您的服务器端代码仅在服务器端提供,而浏览器端代码在浏览器中提供。这肯定需要更多的代码,但从维护的角度来看,这将更直接。
(下面是猴子快速打字)

公共接口声明

// common.ts
export abstract class MyServiceBase {
  abstract doSomething(): void;
}

// if implementations of service will be provided only in Angular implementation, InjectionToken can be used.
export const MY_SERVICE = new InjectionToken<MyServiceBase>('MY_SERVICE');
// otherwise, if server side implementation will be injected by from node process, then should be string only. (For alternative illustrated below in the end).
// export const MY_SERVICE = 'MY_SERVICE';
适用于服务器端和浏览器端的通用应用程序代码

// app.module.ts
@NgModule({
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

// app-browser.service.ts
@Injectable()
export class MyServiceForBrowser extends MyServiceBase {
  constructor() {
    console.log('MyService browser implementation');
  }

  doSomthing(): void {
    // do something meaningful in browser 
  }
}
引导此选项,而不是默认的
AppModule
,以分离实现配置

// app-browser.module.ts
@NgModule({
  imports: [AppModule],
  providers: [{provide: MY_SERVICE, useClass: MyServiceForBrowser}],
  bootstrap: [AppComponent]
})
export class AppBrowserModule {
}
角度应用程序的服务器端 若您可以在Angular应用程序中直接实现服务器端功能,那个么

// app-server.service.ts
@Injectable()
export class MyServiceForServer extends MyServiceBase {
  constructor(@Inject(REQUEST) private request) {
    console.log('MyService server implementation');
  }

  doSomthing(): void {
    // do something meaningful on server
    console.log('request is', this.request);
  }
}
ngExpressEngine
引导服务器端模块

// app-server.module.ts
@NgModule({
  imports: [AppModule],
  providers: [{provide: MY_SERVICE, useClass: MyServiceForServer}],
  bootstrap: [AppComponent]
})
export class AppServerModule {}
服务器的备选服务器端

作为替代方案,
MyServiceForServer
甚至可以从服务器代码中提供。在这种情况下,无需在角度实现中提供实现:

// app-server.module.ts
@NgModule({
  imports: [AppModule],
  bootstrap: [AppComponent]
})
export class AppServerModule {}
相反,请将其作为普通服务器端代码编写:

export class MyServiceForServer extends MyService {
  constructor(private request) {
    console.log('MyService server implementation');
  }

  doSomthing(): void {
    // do something meaningful on server
    console.log('request is', this.request);
  }
}
并作为
外部值注入:

app.get('*', (req: Request, res) => {
  // construct the server side service instance
  const myService = new MyServiceForServer(req);
  // render server side with service instance provided
  res.render(join(DIST_FOLDER, 'browser', 'index.html'), {
    providers: [{provide: MY_SERVICE, useValue: myService}],
    req
  });
});

在这种情况下,请确保您的
MY_服务
令牌是纯字符串,而不是
InjectionToken
实例。

在package.json中设置版本:

"@types/express": "^4.17.4",
"@types/node": "^12.11.1",

浏览器或节点日志中是否出现错误?错误出现在浏览器中您无法在浏览器中访问
请求
,它是从
expressjs
传递到
ng universal
的服务器端对象。因此,在最坏的情况下,您的代码应该执行类似于
if(isServerPlatform(this.platformId)){/*use req*/}
的操作,并注释
@Optional()@Inject(REQUEST)req
。然后在浏览器中,应用程序将不会查看
请求
,而在服务器端呈现时,应用程序会查看。感谢您的详细回答。这并不能解决我的问题,我熟悉
isPlatformServer
isPlatformBrowser
的用法,但我无法成功访问请求对象。投了赞成票,但我还不能接受。可能它与
AppServerModuleNgFactory
有关,因为它是静态的?该图告诉您,
request
对象在浏览器中不可用,因为它只发生在expressjs中的服务器中。所以,您不应该期望它在浏览器中存在。既然您根据自己的评论抱怨浏览器出现错误,那么答案会解释原因。请记住,该请求是用户浏览器
GET
对服务器的请求。此
GET
请求由服务器处理,响应是带有JavaScript等工件的纯
HTML
。然后此响应触发angular应用程序在浏览器中启动。您希望在浏览器中访问什么req obj?另一方面,为了清楚起见,如果您确实希望在浏览器中访问您的请求对象,那么您必须序列化它并将其在响应中传递给浏览器(在标头、cookie、TransferState等内)。然后您可以在浏览器中反序列化它并相应地访问它。这种方式通常不是你想要的东西。只要记住,如果你想做SSR,那么你的angular应用程序将运行2次。一次在服务器上,然后在浏览器中。
"@types/express": "^4.17.4",
"@types/node": "^12.11.1",