Angular 通用 7 不进行 http 调用
Angular universal 7 not making http calls
我最近开始将我的 Angular 7.2.0 应用程序转换为 Angular 通用应用程序。该应用程序成功呈现服务器端,并在快速 PC 和互联网连接上相当快速地传输状态,但不幸的是,在交接之前,呈现的页面丢失了通常从 API.[=26= 获取的任何数据。 ]
我已经将 serverURL
添加到服务器提供的令牌中,并且在呈现服务器端时,所有 http 请求都是使用完全限定的 url 进行的。然而,这似乎并不重要,因为所有 http 调用在完成之前都被取消了!我的服务器未显示对 api 端点的调用,并且客户端记录了 {}
错误(默认显示为 [Error]
)。
我正在使用 TransferStateModule
以及 TransferHttpCacheModule
,但到目前为止没有任何效果。似乎 express-engine 渲染器不会等待异步 http 调用。它会影响组件 ngOnInit
中的 http 调用、服务的 constructor
以及 resolver
中的任何调用,所以我不知道如何获取数据。
对于配置数据之类的东西,我将必要的字段作为令牌注入,并在服务器端呈现时检查该令牌,但我无法对应用程序中的所有数据执行此操作。
以下是我的服务器和应用程序模块的相关部分
app.ts(节点快递服务器)
app.get('*.*', express.static(APP_CONFIG.client_root, {maxAge: 0}));
// Render Angular Universal
if (APP_CONFIG.universal) {
// Our index.html we'll use as our template
const templateFile = HelpersService.tryLoad(join(APP_CONFIG.client_root, './index.html'));
const config = configService.getConfig();
const template = templateFile.toString();
const win = domino.createWindow(template);
const fakeanimation = {
value: () => {
return {
enumerable: true,
configurable: true
};
},
};
global['window'] = win;
global['document'] = {...win.document,
createElement: () => {},
body: {
...win.document.body,
style: {
...win.document.body.style,
transform: fakeanimation,
opacity: fakeanimation,
bottom: fakeanimation,
left: fakeanimation,
}
}
};
global['navigator'] = win.navigator;
global['location'] = win.location;
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('../ssr/ssr.js');
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP),
]
}));
app.set('view engine', 'html');
app.set('views', APP_CONFIG.client_root);
app.get('*', (req, res, next) => {
const protocol = res.locals.protocol || req.protocol;
const showPort = ((APP_CONFIG.port === 80 && protocol === 'http') || (protocol === 'https')) ? false : true;
const serverUrl = `${protocol}://${req.hostname}${showPort ? ':'+APP_CONFIG.port : ''}`;
res.render('index', {
req,
document: template,
url: req.url,
providers: [
{
provide: 'serverURL',
useValue: serverUrl
},
{
provide: 'SERVER_CONFIG',
useValue: config || {}
},
{
provide: 'SERVER_AUTH',
useValue: {signedIn: !!res.locals.auth}
},
]
});
});
}
app.module.ts
@NgModule({
bootstrap: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({appId: 'myapp'}),
BrowserAnimationsModule,
SharedModule,
TransferHttpCacheModule,
BrowserTransferStateModule,
RouterModule.forRoot(
...
app.server.module.ts
@NgModule({
imports: [
// The AppServerModule should import your AppModule followed
// by the ServerModule from @angular/platform-server.
AppModule,
ServerModule,
ServerTransferStateModule,
ModuleMapLoaderModule // <-- *Important* to have lazy-loaded routes work
],
// Since the bootstrapped component is not inherited from your
// imported AppModule, it needs to be repeated here.
bootstrap: [AppComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: ServerSideRequestInterceptor,
multi: true,
},
]
})
export class AppServerModule {}
ServerSideRequestInterceptor
读取 serverURL
注入令牌,并将其添加到所有以 /
开头的请求。
我觉得我离破解这个问题很近了,但是我一辈子都不知道如何让它等待我的应用程序中的 http 调用。
编辑:
这是我使用 working universal 和 angular 7 制作的 Repo:
https://github.com/swimmadude66/AngularPWASeed/tree/universal7
感谢@CaerusKaru 在@nguniversal 问题页面解决了这个问题! https://github.com/angular/universal/issues/1046#issuecomment-455408250
本质上,问题是 interceptor
我用来将完整的服务器路径附加到 api 调用。它使用 Object.assign(request, {url: fullServerUrl});
为所有以 /
开头的 http 请求设置新的 url。适当的方法显然是 request.clone({url: fullServerUrl});
并且更改一个片段会导致数据像急流一样流动。
希望这对其他人有帮助,我将把 repro-repo(很难说和打字)变成 Angular7 和 Universal 的样板作为工作的起点。
我最近开始将我的 Angular 7.2.0 应用程序转换为 Angular 通用应用程序。该应用程序成功呈现服务器端,并在快速 PC 和互联网连接上相当快速地传输状态,但不幸的是,在交接之前,呈现的页面丢失了通常从 API.[=26= 获取的任何数据。 ]
我已经将 serverURL
添加到服务器提供的令牌中,并且在呈现服务器端时,所有 http 请求都是使用完全限定的 url 进行的。然而,这似乎并不重要,因为所有 http 调用在完成之前都被取消了!我的服务器未显示对 api 端点的调用,并且客户端记录了 {}
错误(默认显示为 [Error]
)。
我正在使用 TransferStateModule
以及 TransferHttpCacheModule
,但到目前为止没有任何效果。似乎 express-engine 渲染器不会等待异步 http 调用。它会影响组件 ngOnInit
中的 http 调用、服务的 constructor
以及 resolver
中的任何调用,所以我不知道如何获取数据。
对于配置数据之类的东西,我将必要的字段作为令牌注入,并在服务器端呈现时检查该令牌,但我无法对应用程序中的所有数据执行此操作。
以下是我的服务器和应用程序模块的相关部分
app.ts(节点快递服务器)
app.get('*.*', express.static(APP_CONFIG.client_root, {maxAge: 0}));
// Render Angular Universal
if (APP_CONFIG.universal) {
// Our index.html we'll use as our template
const templateFile = HelpersService.tryLoad(join(APP_CONFIG.client_root, './index.html'));
const config = configService.getConfig();
const template = templateFile.toString();
const win = domino.createWindow(template);
const fakeanimation = {
value: () => {
return {
enumerable: true,
configurable: true
};
},
};
global['window'] = win;
global['document'] = {...win.document,
createElement: () => {},
body: {
...win.document.body,
style: {
...win.document.body.style,
transform: fakeanimation,
opacity: fakeanimation,
bottom: fakeanimation,
left: fakeanimation,
}
}
};
global['navigator'] = win.navigator;
global['location'] = win.location;
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('../ssr/ssr.js');
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP),
]
}));
app.set('view engine', 'html');
app.set('views', APP_CONFIG.client_root);
app.get('*', (req, res, next) => {
const protocol = res.locals.protocol || req.protocol;
const showPort = ((APP_CONFIG.port === 80 && protocol === 'http') || (protocol === 'https')) ? false : true;
const serverUrl = `${protocol}://${req.hostname}${showPort ? ':'+APP_CONFIG.port : ''}`;
res.render('index', {
req,
document: template,
url: req.url,
providers: [
{
provide: 'serverURL',
useValue: serverUrl
},
{
provide: 'SERVER_CONFIG',
useValue: config || {}
},
{
provide: 'SERVER_AUTH',
useValue: {signedIn: !!res.locals.auth}
},
]
});
});
}
app.module.ts
@NgModule({
bootstrap: [
AppComponent
],
imports: [
BrowserModule.withServerTransition({appId: 'myapp'}),
BrowserAnimationsModule,
SharedModule,
TransferHttpCacheModule,
BrowserTransferStateModule,
RouterModule.forRoot(
...
app.server.module.ts
@NgModule({
imports: [
// The AppServerModule should import your AppModule followed
// by the ServerModule from @angular/platform-server.
AppModule,
ServerModule,
ServerTransferStateModule,
ModuleMapLoaderModule // <-- *Important* to have lazy-loaded routes work
],
// Since the bootstrapped component is not inherited from your
// imported AppModule, it needs to be repeated here.
bootstrap: [AppComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: ServerSideRequestInterceptor,
multi: true,
},
]
})
export class AppServerModule {}
ServerSideRequestInterceptor
读取 serverURL
注入令牌,并将其添加到所有以 /
开头的请求。
我觉得我离破解这个问题很近了,但是我一辈子都不知道如何让它等待我的应用程序中的 http 调用。
编辑: 这是我使用 working universal 和 angular 7 制作的 Repo: https://github.com/swimmadude66/AngularPWASeed/tree/universal7
感谢@CaerusKaru 在@nguniversal 问题页面解决了这个问题! https://github.com/angular/universal/issues/1046#issuecomment-455408250
本质上,问题是 interceptor
我用来将完整的服务器路径附加到 api 调用。它使用 Object.assign(request, {url: fullServerUrl});
为所有以 /
开头的 http 请求设置新的 url。适当的方法显然是 request.clone({url: fullServerUrl});
并且更改一个片段会导致数据像急流一样流动。
希望这对其他人有帮助,我将把 repro-repo(很难说和打字)变成 Angular7 和 Universal 的样板作为工作的起点。