TypeScript 代码得到执行,但它不应该
TypeScript code getting executed but it shouldn't
我正在使用 TypeScript 和 Rxjs。我正在使用 Rxjs 向服务器发送数据。我还实现了一个自定义拦截器。拦截器 returns 一个 type:0
事件以及来自服务器的响应作为两个单独的事件。我想 type:0
表示请求已发送。
我不想在收到 type:0
事件时做任何事情,所以我检查了代码以忽略它,但我的代码仍然执行一段逻辑,即使事件是 [=15] =].我弄错了吗?
我发送请求的代码是
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(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, …}
我想我从 Rxjs
得到 HttpEvent
,它是 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 不是 return type/interface ServerResponseAPI 的对象,它 return 是订阅操作中的订阅对象,因此您可以 subscription.unsubscribe( ) 如果需要,稍后再说。
2- 响应变量中的内容不是响应,您将那段代码视为同步代码,它不是。
我编写代码的方式几乎没有问题(一些基本问题)
1) 打字稿联盟。
我对打字稿中 union
类型的理解不正确。 HttpEvent
是几种类型的联合,我只能调用所有类型通用的 methods/properties 。
type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;
一个常见的 属性 是 type
。而不是使用 instanceof
比较 HttpEvent
与 HttpResponse
,我必须从 HttpEvent
中获取 type
,然后将其与 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);
}
})
虽然代码的主要问题不是这个,但调试打印有助于提供方向。
我的申请流程是
1) f1函数中的组件调用dataservice的f2函数发送消息this.dataManagementService.addData(this.newData);
2) dataservice 的 f2 调用 backendservice 的 f3 并且还订阅了 observable returned by f3 - this.bs.createData(data).subscribe
3) 后端服务的 f3 发送 post 消息,创建可观察对象并映射响应,return 将映射的可观察对象映射到数据服务的 f2) - this.http.post(this.NEW_DATA_URL,body,httpOptions)
4)拦截器。
我误解了 Observables
或 Rxjs
的异步行为(被 post
使用)并认为来自服务器的数据在这里对我可用 - let response:ServerResponseAPI = this.dataManagementService.addData(this.newData);
但上面只是同步函数调用,此时我得到的是反向路径的 return 值 - 拦截器 -> 后端服务 -> 数据服务。拦截器 returns Observable<HttpEvent<any>>
所以我在 let response:ServerResponseAPI = this.dataManagementService.addData(this.newData)
得到的是拦截器的 Observable
。我应该订阅那个 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");
}
});
我正在使用 TypeScript 和 Rxjs。我正在使用 Rxjs 向服务器发送数据。我还实现了一个自定义拦截器。拦截器 returns 一个 type:0
事件以及来自服务器的响应作为两个单独的事件。我想 type:0
表示请求已发送。
我不想在收到 type:0
事件时做任何事情,所以我检查了代码以忽略它,但我的代码仍然执行一段逻辑,即使事件是 [=15] =].我弄错了吗?
我发送请求的代码是
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(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, …}
我想我从 Rxjs
得到 HttpEvent
,它是 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 不是 return type/interface ServerResponseAPI 的对象,它 return 是订阅操作中的订阅对象,因此您可以 subscription.unsubscribe( ) 如果需要,稍后再说。
2- 响应变量中的内容不是响应,您将那段代码视为同步代码,它不是。
我编写代码的方式几乎没有问题(一些基本问题)
1) 打字稿联盟。
我对打字稿中 union
类型的理解不正确。 HttpEvent
是几种类型的联合,我只能调用所有类型通用的 methods/properties 。
type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;
一个常见的 属性 是 type
。而不是使用 instanceof
比较 HttpEvent
与 HttpResponse
,我必须从 HttpEvent
中获取 type
,然后将其与 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);
}
})
虽然代码的主要问题不是这个,但调试打印有助于提供方向。
我的申请流程是
1) f1函数中的组件调用dataservice的f2函数发送消息this.dataManagementService.addData(this.newData);
2) dataservice 的 f2 调用 backendservice 的 f3 并且还订阅了 observable returned by f3 - this.bs.createData(data).subscribe
3) 后端服务的 f3 发送 post 消息,创建可观察对象并映射响应,return 将映射的可观察对象映射到数据服务的 f2) - this.http.post(this.NEW_DATA_URL,body,httpOptions)
4)拦截器。
我误解了 Observables
或 Rxjs
的异步行为(被 post
使用)并认为来自服务器的数据在这里对我可用 - let response:ServerResponseAPI = this.dataManagementService.addData(this.newData);
但上面只是同步函数调用,此时我得到的是反向路径的 return 值 - 拦截器 -> 后端服务 -> 数据服务。拦截器 returns Observable<HttpEvent<any>>
所以我在 let response:ServerResponseAPI = this.dataManagementService.addData(this.newData)
得到的是拦截器的 Observable
。我应该订阅那个 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");
}
});