TypeScript代码正在执行,但不应该

问题描述 投票:1回答:2

我正在使用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

angular rxjs6
2个回答
0
投票

看一下这段代码:

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
投票

我编写代码的方式几乎没有问题(一些基本问题)>>

1)打字稿联合。我对打字稿中union类型的理解不正确。 HttpEvent是几种类型的并集,我只能调用所有类型都通用的方法/属性。

type HttpEvent<T> = HttpSentEvent | HttpHeaderResponse | HttpResponse<T> | HttpProgressEvent | HttpUserEvent<T>;

[一个共同的属性是type。不必使用HttpEventHttpResponseinstanceof进行比较,而是必须从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).subscribe3)backendservice的f3发送发布消息,创建可观察的并映射响应,将map的可观察返回给dataservice的f2)-this.http.post(this.NEW_DATA_URL,body,httpOptions)4)拦截器。

[我误解了ObservablesRxjs的异步行为(由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");
            }
          });
© www.soinside.com 2019 - 2024. All rights reserved.