使用 Angular Universal 时,在组件的 ngOnInit 中发出 http 请求是否有问题?
Is there something wrong with making an http request in the ngOnInit of a component when using Angular Universal?
我已经 运行 我的 Angular 应用程序通过 ng serve for development 并且没有遇到任何错误。然而,当使用 SSR 时,每当我加载一个组件时,我的服务器日志中都会出现错误,该组件发出 http 请求作为其 ngOnInit 方法的一部分。我的策略有问题吗?
我没有通过谷歌搜索我的错误找到任何有用的信息。我应该在页面完全加载之前等待提出请求,还是使用其他方法?如果是这样,我该怎么做?
我正在使用 http-proxy-middleware 包向 Django 服务器发送请求。 https://github.com/chimurai/http-proxy-middleware
这是在 ngOnInit 中发出请求时出现的错误:
ERROR Error
at XMLHttpRequest.send (C:\{...}\dist\{...}\server\main.js:201490:19)
at Observable.rxjs__WEBPACK_IMPORTED_MODULE_1__.Observable [as _subscribe] (C:\{...}\dist\{...}\server\main.js:23724:17)
at Observable._trySubscribe (C:\{...}\dist\{...}\server\main.js:186583:25)
at Observable.subscribe (C:\{...}\dist\{...}\server\main.js:186569:22)
at scheduleTask (C:\{...}\dist\{...}\server\main.js:106745:32)
at Observable.rxjs__WEBPACK_IMPORTED_MODULE_7__.Observable [as _subscribe] (C:\{...}\dist\{...}\server\main.js:106807:13)
at Observable._trySubscribe (C:\{...}\dist\{...}\server\main.js:186583:25)
at Observable.subscribe (C:\{...}\dist\{...}\server\main.js:186569:22)
at subscribeToResult (C:\{...}\dist\{...}\server\main.js:196664:23)
at MergeMapSubscriber._innerSub (C:\{...}\dist\{...}\server\main.js:191854:116)
这是我的测试组件的相关部分:
export class TestComponent implements OnInit {
output: String = "The server is not running or is not connected"
constructor(private httpTestService: HttpTestService) { }
ngOnInit(): void {
this.testGetRequest();
}
testGetRequest() {
this.httpTestService.testGetRequest().subscribe(temp => {
this.output = temp.message; // response is json with a 'message' attribute
});
}
}
这是我的 HttpTestService 的相关部分:
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) { }
testGetRequest(): Observable<any> {
return this.http.get('/api/endpoint1');
}
我认为我的 server.ts 这部分内容可能很重要:
import { createProxyMiddleware } from 'http-proxy-middleware';
export function app() {
const server = express();
const distFolder = join(process.cwd(), 'dist/.../browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// re-route requests to /api/ to the django REST api
server.use('/api/**', createProxyMiddleware({ target: 'http://localhost:8000', changeOrigin: true }));
即使在 运行 SSR 时,应用程序也能正常运行,除了我在服务器控制台中遇到的错误。
进行 HTTP 调用时应使用绝对 URL。 docs
所以问题可能出在这里
testGetRequest(): Observable<any> {
return this.http.get('/api/endpoint1');
}
要修复它,您可以使用将相对 URL 更改为绝对 URL 的拦截器,并在 AppServerModule 中提供该拦截器。
拦截器是:
import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Inject, Injectable, Optional } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { Request } from 'express';
@Injectable()
export class UniversalInterceptor implements HttpInterceptor {
constructor(@Optional() @Inject(REQUEST) protected request: Request) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
let serverReq: HttpRequest<any> = req;
if (this.request && req.url.indexOf('http') !== 0) {
let newUrl = `${this.request.protocol}://${this.request.get('host')}`;
if (!req.url.startsWith('/')) {
newUrl += '/';
}
newUrl += req.url;
serverReq = req.clone({url: newUrl});
}
return next.handle(serverReq);
}
}
AppServerModule 是
@NgModule({
imports: [
...
],
bootstrap: [AppComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UniversalInterceptor,
multi: true,
},
],
})
export class AppServerModule {}
希望对您有所帮助
我已经 运行 我的 Angular 应用程序通过 ng serve for development 并且没有遇到任何错误。然而,当使用 SSR 时,每当我加载一个组件时,我的服务器日志中都会出现错误,该组件发出 http 请求作为其 ngOnInit 方法的一部分。我的策略有问题吗?
我没有通过谷歌搜索我的错误找到任何有用的信息。我应该在页面完全加载之前等待提出请求,还是使用其他方法?如果是这样,我该怎么做?
我正在使用 http-proxy-middleware 包向 Django 服务器发送请求。 https://github.com/chimurai/http-proxy-middleware
这是在 ngOnInit 中发出请求时出现的错误:
ERROR Error
at XMLHttpRequest.send (C:\{...}\dist\{...}\server\main.js:201490:19)
at Observable.rxjs__WEBPACK_IMPORTED_MODULE_1__.Observable [as _subscribe] (C:\{...}\dist\{...}\server\main.js:23724:17)
at Observable._trySubscribe (C:\{...}\dist\{...}\server\main.js:186583:25)
at Observable.subscribe (C:\{...}\dist\{...}\server\main.js:186569:22)
at scheduleTask (C:\{...}\dist\{...}\server\main.js:106745:32)
at Observable.rxjs__WEBPACK_IMPORTED_MODULE_7__.Observable [as _subscribe] (C:\{...}\dist\{...}\server\main.js:106807:13)
at Observable._trySubscribe (C:\{...}\dist\{...}\server\main.js:186583:25)
at Observable.subscribe (C:\{...}\dist\{...}\server\main.js:186569:22)
at subscribeToResult (C:\{...}\dist\{...}\server\main.js:196664:23)
at MergeMapSubscriber._innerSub (C:\{...}\dist\{...}\server\main.js:191854:116)
这是我的测试组件的相关部分:
export class TestComponent implements OnInit {
output: String = "The server is not running or is not connected"
constructor(private httpTestService: HttpTestService) { }
ngOnInit(): void {
this.testGetRequest();
}
testGetRequest() {
this.httpTestService.testGetRequest().subscribe(temp => {
this.output = temp.message; // response is json with a 'message' attribute
});
}
}
这是我的 HttpTestService 的相关部分:
import { HttpClient } from '@angular/common/http';
constructor(private http: HttpClient) { }
testGetRequest(): Observable<any> {
return this.http.get('/api/endpoint1');
}
我认为我的 server.ts 这部分内容可能很重要:
import { createProxyMiddleware } from 'http-proxy-middleware';
export function app() {
const server = express();
const distFolder = join(process.cwd(), 'dist/.../browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// re-route requests to /api/ to the django REST api
server.use('/api/**', createProxyMiddleware({ target: 'http://localhost:8000', changeOrigin: true }));
即使在 运行 SSR 时,应用程序也能正常运行,除了我在服务器控制台中遇到的错误。
进行 HTTP 调用时应使用绝对 URL。 docs
所以问题可能出在这里
testGetRequest(): Observable<any> {
return this.http.get('/api/endpoint1');
}
要修复它,您可以使用将相对 URL 更改为绝对 URL 的拦截器,并在 AppServerModule 中提供该拦截器。
拦截器是:
import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Inject, Injectable, Optional } from '@angular/core';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { Request } from 'express';
@Injectable()
export class UniversalInterceptor implements HttpInterceptor {
constructor(@Optional() @Inject(REQUEST) protected request: Request) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
let serverReq: HttpRequest<any> = req;
if (this.request && req.url.indexOf('http') !== 0) {
let newUrl = `${this.request.protocol}://${this.request.get('host')}`;
if (!req.url.startsWith('/')) {
newUrl += '/';
}
newUrl += req.url;
serverReq = req.clone({url: newUrl});
}
return next.handle(serverReq);
}
}
AppServerModule 是
@NgModule({
imports: [
...
],
bootstrap: [AppComponent],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UniversalInterceptor,
multi: true,
},
],
})
export class AppServerModule {}
希望对您有所帮助