Угловой универсальный 7 не совершающий http звонков - PullRequest
0 голосов
/ 18 января 2019

Я недавно начал преобразовывать мое приложение Angular 7.2.0 в универсальное приложение Angular. Приложение успешно рендерится на стороне сервера и довольно быстро передает состояние на быстрых ПК и интернет-соединениях, но, к сожалению, до момента передачи на отображаемой странице отсутствуют какие-либо данные, обычно извлекаемые из API.

Я добавил serverURL к предоставленному токену с сервера, и при рендеринге на стороне сервера все http-запросы выполняются с использованием полного URL-адреса. Однако, похоже, это не имеет значения, поскольку все http-вызовы отменяются до их завершения! Мой сервер не показывает вызовов к конечным точкам API, и клиент регистрирует ошибку {} (которая по умолчанию отображается как [Error]).

Я использую TransferStateModule, а также TransferHttpCacheModule, но пока ничего не получалось. Кажется, что рендер экспресс-движка просто не будет ждать асинхронных http-вызовов. Он влияет на вызовы http в ngOnInit компонентов, constructor s служб и любые в resolver s, поэтому я не знаю, как еще получить данные.

Для таких вещей, как данные конфигурации, я вставляю необходимые поля в качестве токена и проверяю этот токен при рендеринге на стороне сервера, но не могу сделать это для всех данных в приложении.

Ниже приведены соответствующие разделы моего сервера и модулей приложения.

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-вызовов в моем приложении.

EDIT: Вот репо, которое я сделал с рабочим универсальным и угловым 7: https://github.com/swimmadude66/AngularPWASeed/tree/universal7

1 Ответ

0 голосов
/ 18 января 2019

Спасибо @CaerusKaru за решение этой проблемы на странице проблем @nguniversal! https://github.com/angular/universal/issues/1046#issuecomment-455408250

По сути, проблема была в interceptor, который я использую для добавления полного пути к серверу к вызовам API. Он использовал Object.assign(request, {url: fullServerUrl}); для установки нового URL-адреса для всех http-запросов, начинающихся с /. Подходящий метод, по-видимому, request.clone({url: fullServerUrl});, и изменение этого фрагмента привело к тому, что данные стали течь как стремительный поток.

Надеюсь, это поможет кому-то еще, и я буду превращать репро-репо (сложно сказать и напечатать) в шаблон Angular7 и Universal в качестве рабочей стартовой точки.

...