我正在使用TypeScript和Rxjs。我正在使用Rxjs将数据发送到服务器。我还实现了自定义拦截器。拦截器返回type:0
事件以及服务器的响应作为两个单独的事件。我想type:0
表示请求已发送。
当接收到type:0
事件时,我不想做任何事情,因此我已经在代码中进行了检查以忽略它,但是即使事件为type:0
,我的代码仍会执行一段逻辑。我做错了吗?
我发送请求的代码是
let response:ServerResponseAPI = this.dataManagementService.addData(this.newData);
console.log("add practice question - response is ",response); //I see this print
if (response != null) { //for type:0, this should be null but isn't
let isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(response);
if (isResponseStructureOK) {
console.log("received response from server: " + response.result);
let dialogComponentRef: ComponentRef<DialogBoxComponent> = this.maxFilesDialogContainerRef.createComponent(this.dialogFactory);
dialogComponentRef.instance.dialogMessage = response.result + ": " + response['additional-info'];
dialogComponentRef.instance.dialogID = "maxFilesDialog";
dialogComponentRef.instance.dialogShow();
return;
} else { //response structure not ok
console.log("received incorrect response structure from server: ", response);
let dialogComponentRef: ComponentRef<DialogBoxComponent> = this.maxFilesDialogContainerRef.createComponent(this.dialogFactory);
dialogComponentRef.instance.dialogMessage = "Server error";
dialogComponentRef.instance.dialogID = "maxFilesDialog";
dialogComponentRef.instance.dialogShow();
return;
}
} //end of not null response
addData是
addData(data:Data):ServerResponseAPI{
console.log("In DataManagementService: addData: ",data);
return this.bs.createData(data).subscribe((resBody/*:any*/)=>{
if(resBody != null) { //null means that the response wasn't an HttpResponse but probably some internal Rxjs event (eg type 0)
console.log('response from server:', resBody);
<ServerResponseAPI>resBody; //returning response body which is of type ServerResponseAPI;
}
else null; //this means type0 event
});
}
和bs.createData是
public createData(data:Data):any{
console.log('contacting server at '+this.API_URL +this.NEW_DATA_URL +" with data "+data+ " with httpOptions "+httpOptions.withCredentials + ","+httpOptions.headers );
let newData = new DataAPI(data)
let body = JSON.stringify(newData);
return this.http.post(this.NEW_DATA_URL,body,httpOptions)
.map(response => { //I suppose this could be any event from custom interceptor
if(response instanceof HttpResponse)
{
console.log('response from backend service:', response);
let result = <HttpResponse<any>>response;
return result.body; //return body of response which ideally should be of type ServerResponseAPI
}
else {
console.log("not an http response")
return null; //returning null for non-HttpResponse type
}
})
.catch(this.handleError); //error handler if Observable fails
}
拦截器是
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log("outgoing request",request);
const idToken = localStorage.getItem("id_token"); //JWT authentication stuff
console.log("id token is "+idToken);
if (idToken) {
const cloned = request.clone({
headers: request.headers.set("X-Auth-Token",
idToken)
});
console.log("new outgoing request", request);
return next.handle(cloned)
.do((ev: any) => {
console.log("got an event",ev)
})
.catch(errorResponse => {
console.log("caught error from server",errorResponse)
return observableThrowError(errorResponse);
});
}
else {
return next
.handle(request)
.do((ev: any) => {
console.log("got an event",ev)
})
.catch(errorResponse => {
console.log("caught error from server",errorResponse)
return observableThrowError(errorResponse);
});
}
}
[当我运行代码时,我看到了我不应该看到的消息
got an event {type: 0}
new-data.component.ts:255 add data- response is Subscriber {closed: false, _parent: null, _parents: null, _subscriptions: Array(1), syncErrorValue: null, …}
new-practice-question.component.ts:270 received incorrect response structure from server: Subscriber {closed: false, _parent: null, _parents: null, _subscriptions: Array(1), syncErrorValue: null, …}
我想我是从HttpEvent
那里获得的Rxjs
,它是HttpResponse的并集。
type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;
如何检查HttpEvent
的类型为HttpResponse
?
看一下这段代码:
addData(data:Data):ServerResponseAPI{
console.log("In DataManagementService: addData: ",data);
return this.bs.createData(data).subscribe((resBody/*:any*/)=>{ (...)
现在先看几行:
let response:ServerResponseAPI = this.dataManagementService.addData(this.newData);
这里有一些不正确的地方:
1- addData不会返回类型/接口ServerResponseAPI的对象,它会从您的订阅操作中返回一个订阅对象,以便以后可以根据需要执行subscription.unsubscribe()。
2-您的响应变量中的内容不是响应,您正在将这段代码视为同步,而不是同步。
我编写代码的方式几乎没有问题(一些基本问题)>>
1)打字稿联合。我对打字稿中union
类型的理解不正确。 HttpEvent
是几种类型的并集,我只能调用所有类型都通用的方法/属性。
type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;
[一个共同的属性是
type
。不必使用HttpEvent
将HttpResponse
与instanceof
进行比较,而是必须从type
中获取HttpEvent
,然后将其与HttpEventType
进行比较,如拦截器代码中的以下所示
return next .handle(request) //next.handle is passing the transformed request (if transformed by intercept here) to the next handler. next.handle returns a Rx stream .do((ev: HttpEvent<any>) => { // To intercept the response coming back from the server, we can simply hook on the do(..) operator. `do` applies additional Rx operators on the stream returned by next.handle console.log("got an event",ev) if (ev.type === HttpEventType.Response) { console.log('event of type Http response'); } else if (ev.type === HttpEventType.Sent) { console.log(" event of type httpsent"); } else if(ev.type === HttpEventType.DownloadProgress){ console.log("event of type download progress"); } else if (ev.type === HttpEventType.UploadProgress) { console.log("event of type upload progress"); } else if (ev.type === HttpEventType.User) { console.log("event of type user progress"); }else if (ev.type === HttpEventType.ResponseHeader) { console.log("event of type response header") } else { console.log("don't know type",ev.type); } })
虽然,代码的主要问题不是这个,但调试打印有助于指明方向。
我的申请流程是
函数f1中的1)组件调用数据服务的函数f2发送消息this.dataManagementService.addData(this.newData);
2)dataservice的f2调用backendservice的f3,并且还订阅了f3返回的observable-this.bs.createData(data).subscribe
3)backendservice的f3发送发布消息,创建可观察的并映射响应,将map的可观察返回给dataservice的f2)-this.http.post(this.NEW_DATA_URL,body,httpOptions)
4)拦截器。
[我误解了Observables
的Rxjs
的异步行为(由post
使用),并认为服务器的数据在这里对我可用-let response:ServerResponseAPI = this.dataManagementService.addData(this.newData);
但是上面只是同步函数的调用,那时我得到的是反向路径的返回值-拦截器-> backendservice-> dataservice。拦截器返回Observable<HttpEvent<any>>
,所以我在let response:ServerResponseAPI = this.dataManagementService.addData(this.newData)
处得到的是拦截器的Observable
。我应该订阅该观察报告,并等待那里的答复。请注意,由于拦截器可以发送许多消息,因此我必须检查类型以查看何时获得响应。
// Observable从拦截器订阅到这里一直返回
this.dataService.addData(this.newData).subscribe((ev:HttpEvent<any>)=>{
console.log("add data - response is ",ev);
if(ev.type === HttpEventType.Response) {
console.log('response from server: returning body '+ev.body);
let isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(ev.body);
if (isResponseStructureOK) {
let response:ServerResponseAPI = ev.body;
console.log("received response from server: " + response.result);
let dialogComponentRef: ComponentRef<DialogBoxComponent> = this.maxFilesDialogContainerRef.createComponent(this.dialogFactory);
dialogComponentRef.instance.dialogMessage = response.result + ": " + response['additional-info'];
dialogComponentRef.instance.dialogID = "maxFilesDialog";
//TODOM - once this view gets added, I am not deleting it from the viewcontainer once the dialog's OK is pressed. Need to find a way to do this.
dialogComponentRef.instance.dialogShow();
} else {
console.log("received incorrect response structure from server: ", ev.body);
let dialogComponentRef: ComponentRef<DialogBoxComponent> = this.maxFilesDialogContainerRef.createComponent(this.dialogFactory);
dialogComponentRef.instance.dialogMessage = "Server error";
dialogComponentRef.instance.dialogID = "maxFilesDialog";
//TODOM - once this view gets added, I am not deleting it from the viewcontainer once the dialog's OK is pressed. Need to find a way to do this.
dialogComponentRef.instance.dialogShow();
}
}
else {
console.log("not response. ignoring");
}
});