如何拦截调用并动态返回 JSON 文件(没有 "import")
How to intercept call and serve back JSON file dynamically (without "import")
我有一个文件夹和 json 文件的脚手架来模拟 API 的路径。当我 运行 npm run start:mock
、LocalMockInterceptor
被配置时,例如通过本地 Folder A/Folder B/C.json[=31 的 http 调用替换对 host/A/B/C 的调用=]. JSON 文件由超出此处范围的单独脚本生成。我不能像许多教程那样使用 "import",因为我需要一个通用的解决方案,因为我正在模拟的 API 会随着时间的推移而发展(文件夹和文件的脚手架也会如此)。
/**
* The idea is to only build this into the bundle if we specify so (e.g. on TeamCity, on your localhost), where you don't want to rely
* on external resources for development
* No conditionals in the code bundle! No configuration files or database dependency.
*/
import {
HttpInterceptor,
HttpResponse,
HttpHandler,
HttpRequest,
HttpEvent,
HttpClient,
HttpHeaders
} from '@angular/common/http';
import { Injectable, Injector } from '@angular/core';
import { Observable, of } from 'rxjs';
import { ErrorService } from './error.service';
const devAssetsFolder = 'assets';
@Injectable()
export class LocalMockInterceptor implements HttpInterceptor {
constructor(
private errorService: ErrorService,
private injector: Injector,
private http: HttpClient
) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
var promise = this.getJSON(path).toPromise();
const jsonheaders = new HttpHeaders();
jsonheaders.set('Content-Type', 'application/json');
let json2;
promise
.then(json => {
console.log(json);
json2 = json;
})
.catch(error => console.log(error));
Promise.all([promise]);
console.log(json2);
return of(
new HttpResponse({ status: 200, body: json2, headers: jsonheaders })
);
}
private getJSON(jsonPath: string): Observable<any> {
return this.http.get(jsonPath);
}
}
- 第一个条件是避免无限循环,因为我在拦截器中发送 HTTP 请求
- 根据URL得到JSON文件的路径很自然
在我看来,我必须将 JSON Observable 转换为一个 promise,这样我就可以等待它完成,然后再将 json 重新包装到返回的 Observable 中.然而,在调试时,似乎 Promise.all
没有等待承诺完成(json2
在下一行未定义),我最终发送了一个空的 http 正文......
- 如何修复此 rxjs 承诺?
- 内部 HTTP 调用是我唯一的选择吗?
- 有没有办法不依赖承诺?你能想出更好的方法来实现这个目标吗?
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
return this.getJSON(path).pipe(map(result => {
const jsonheaders = new HttpHeaders({ 'Content-Type': 'application/json' });
return
new HttpResponse({ status: 200, body: result, headers: jsonheaders });
}), // you can also add catchError here
);
}
在拦截方法中,您可以 return 一个可观察对象。所以你的 getJSON
方法 return 是一个可观察的,我们添加了一个映射函数,它将结果映射到新的 http 响应。如果您的响应已经正确 headers 您甚至不需要管道和映射函数,您可以这样做:
return this.getJSON(path); // it's an observable, so it's OK.
您是否尝试过在拦截器中修改目标 URL?你想做一个 API 调用 return 一些 JSON 但不是调用动态 API,你只是想调用你静态服务器所以它可以 return预定义JSON.
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const fakeUrl = `${devAssetsFolder}${request.url}.json`;
const fakeRequest = request.clone({url: fakeUrl});
return next.handle(request);
}
我有一个文件夹和 json 文件的脚手架来模拟 API 的路径。当我 运行 npm run start:mock
、LocalMockInterceptor
被配置时,例如通过本地 Folder A/Folder B/C.json[=31 的 http 调用替换对 host/A/B/C 的调用=]. JSON 文件由超出此处范围的单独脚本生成。我不能像许多教程那样使用 "import",因为我需要一个通用的解决方案,因为我正在模拟的 API 会随着时间的推移而发展(文件夹和文件的脚手架也会如此)。
/**
* The idea is to only build this into the bundle if we specify so (e.g. on TeamCity, on your localhost), where you don't want to rely
* on external resources for development
* No conditionals in the code bundle! No configuration files or database dependency.
*/
import {
HttpInterceptor,
HttpResponse,
HttpHandler,
HttpRequest,
HttpEvent,
HttpClient,
HttpHeaders
} from '@angular/common/http';
import { Injectable, Injector } from '@angular/core';
import { Observable, of } from 'rxjs';
import { ErrorService } from './error.service';
const devAssetsFolder = 'assets';
@Injectable()
export class LocalMockInterceptor implements HttpInterceptor {
constructor(
private errorService: ErrorService,
private injector: Injector,
private http: HttpClient
) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
var promise = this.getJSON(path).toPromise();
const jsonheaders = new HttpHeaders();
jsonheaders.set('Content-Type', 'application/json');
let json2;
promise
.then(json => {
console.log(json);
json2 = json;
})
.catch(error => console.log(error));
Promise.all([promise]);
console.log(json2);
return of(
new HttpResponse({ status: 200, body: json2, headers: jsonheaders })
);
}
private getJSON(jsonPath: string): Observable<any> {
return this.http.get(jsonPath);
}
}
- 第一个条件是避免无限循环,因为我在拦截器中发送 HTTP 请求
- 根据URL得到JSON文件的路径很自然
在我看来,我必须将 JSON Observable 转换为一个 promise,这样我就可以等待它完成,然后再将 json 重新包装到返回的 Observable 中.然而,在调试时,似乎
Promise.all
没有等待承诺完成(json2
在下一行未定义),我最终发送了一个空的 http 正文......- 如何修复此 rxjs 承诺?
- 内部 HTTP 调用是我唯一的选择吗?
- 有没有办法不依赖承诺?你能想出更好的方法来实现这个目标吗?
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (request.url.endsWith('.json')) return next.handle(request);
console.log(
` >>> Mock Interceptor >>> ${request.url} has been intercepted`
);
const path = `${devAssetsFolder}${request.url}.json`;
return this.getJSON(path).pipe(map(result => {
const jsonheaders = new HttpHeaders({ 'Content-Type': 'application/json' });
return
new HttpResponse({ status: 200, body: result, headers: jsonheaders });
}), // you can also add catchError here
);
}
在拦截方法中,您可以 return 一个可观察对象。所以你的 getJSON
方法 return 是一个可观察的,我们添加了一个映射函数,它将结果映射到新的 http 响应。如果您的响应已经正确 headers 您甚至不需要管道和映射函数,您可以这样做:
return this.getJSON(path); // it's an observable, so it's OK.
您是否尝试过在拦截器中修改目标 URL?你想做一个 API 调用 return 一些 JSON 但不是调用动态 API,你只是想调用你静态服务器所以它可以 return预定义JSON.
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const fakeUrl = `${devAssetsFolder}${request.url}.json`;
const fakeRequest = request.clone({url: fakeUrl});
return next.handle(request);
}