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>;

如何检查 HttpEventHttpResponse 类型?

看看你的这段代码:

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 比较 HttpEventHttpResponse,我必须从 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)拦截器。

我误解了 ObservablesRxjs 的异步行为(被 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");
            }
          });