mp-2

本文深入探讨Angular中HTTP拦截器的实现与应用,包括如何设置header、处理请求响应以及错误处理策略。同时,讲解Angular 2中的AsyncPipe用法,帮助开发者更好地管理异步数据流。

http拦截器,参考:
官网:https://angular.cn/guide/http#intercepting-requests-and-responses
设置header:https://blog.youkuaiyun.com/wanglui1990/article/details/78796662
https://www.cnblogs.com/changyaoself/p/8539048.html
https://www.cnblogs.com/leejay6567/p/9462758.html
https://juejin.im/post/5b59c89de51d45190a4336d8#comment
https://www.jianshu.com/p/165c0b6d1475

Angular 2 AsyncPipe,参考:
https://segmentfault.com/a/1190000008759314

创建拦截器的service:
ng g service share/http-interceptor

在share.module中:

providers:[
  {
    provide:HTTP_INTERCEPTORS,
    useClass:HttpInterceptorService, // HttpInterceptorService自己服务的名字,其他都是固定的。
    multi:true
  }
]

service:

import '../utils/base64.js';
declare var Base64: any;

const baseurl = '';

@Injectable({
  providedIn: 'root'
})
export class HttpInterceptorService implements HttpInterceptor {

  constructor(private nzMessageService: NzMessageService,) {
  }
  
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log("req:",req);
    console.log("req-params:",req.params);
    
    // 处理request的参数:可以什么都不做;或者增加header里面的token。
    req = req.clone({
      url: `${baseurl}${req.url}`,
      params: req.params.delete('__isNeedHeader'),
      body: req.body instanceof Object ? this.deleteOwnProperty(req.body, '__isNeedHeader') : null,
    })
    
    // 回调函数:
    return next.handle(req)
      .pipe(
        retry(2), /*失败时重试2次,可自由设置(共执行n+1次)*/
        tap(res=>{ // 任意执行,打印res查看数据
          console.log("tap:",res);
        }),
        filter(res => res instanceof HttpResponse), // 过滤HttpResponse,还会有一个其他的格式,没有用的,eg:{type: 0}
        map((res: HttpResponse<any>) => this.handleSuccess(res)), // 没有发生异常,就执行success
        // catchError(this.handleError.bind(this)),
        catchError(error=>this.handleError(error)) // 接口发生异常了,那么走错误的方法
      )
  }
  
  // 成功
  handleSuccess(res:HttpResponse<any>):HttpEvent<any> {
    const resHeaders =res.headers; // 头
    console.log("resHeaders:",resHeaders);
    const status_code = resHeaders.get('status_code')|| resHeaders.get('Status_code'); // 头status
    const total =resHeaders.get('x-total-count')||resHeaders.get('x-Total-Count'); // 头 tatal
    const data= res.body; // res.body
    console.log("total:",total);
    
    if(status_code==='200'||!status_code){ // 真正的成功(我们用headers里面的status,200或者不存在是成功)
      if(!!total){
        console.log("total:",total);
        return res.clone({
          body:{data:res.body,total:total},
          // body:{data,total}
        });
      }else{
        return res;
      }
    }else { // 错误:headers里面有加密的错误信息
      console.log("Base64:",Base64);
      const base64= new Base64();
      let status_msg = resHeaders.get('status_msg')||resHeaders.get('Status_msg')||'服务器异常';
      status_msg = base64.decode(status_msg); // 错误的写法,汉字无法解析的。
      /*去掉了前后的双引号*/
      if(status_msg[0]==='"'){
        status_msg= status_msg.slice(1,status_msg.length); // 默认第二个参数不传
      }
      if(status_msg[status_msg.length-1]=='"'){
        status_msg= status_msg.slice(0,status_msg.length-1); // 第二个参数传-1即可。
      }
      throw new HttpErrorResponse({ // 重新抛出一个http的错误异常(模拟500情况的数据结构)。
        error:null,
        headers:res.headers,
        status:parseInt(status_code),
        statusText:status_msg,
        url:res.url,
      })
    }
    console.log("成功res:",res);
    // return res; // 最开始什么都没有的时候,必须需要一个返回。
  }


  // 失败:404,500,
  handleError(error){
    console.log("失败error:",error);
    console.log("error里面的error-evnet:",error.error instanceof ErrorEvent);
    if(error.error instanceof ErrorEvent){ // 
      console.log('error-if');
      console.error('An error occurred:', error.error.message);
      return throwError((error.error.message));
    }else{ // 404,500,
      console.log('error-else');
      let status_msg = error.statusText||'服务器异常';
      if(!!error&&error.status===1000){
        // goToLogin:跳转到登录页
        // this.authService.goToLoginPage(); // this.router.navigate(['/pages/login']);
        return;
      }
      if(!!error&&error.status===404){
        status_msg= '请求的接口不存在';
      }
      // 500的时候,没有取到明确的 错误信息(头部的错误信息)
      this.nzMessageService.error(status_msg);
      return throwError(status_msg); // 在浏览器中抛出一个异常
    }
  }

  // 删除对象的属性:
  private deleteOwnProperty(obj: Object, field: string) {
    if (obj.hasOwnProperty(field)) {
      delete obj[field];
    }
    return obj;
  }
}

注:我觉得没有使用baseService好,因为错误的时候,并没有取到错误信息,且传参不舒服。

// 500时候的错误返回:
HttpErrorResponse {headers: HttpHeaders, status: 500, statusText: "Internal Server Error", url: "http://xxx.xxxx.com:4200/marketplace-web/api/product/get-productAll/aa?page=1&size=5", ok: false,}
	error: null
	headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
	message: "Http failure response for http://xxx.xxx.com:4200/marketplace-web/api/product/get-productAll/aa?page=1&size=5: 500 Internal Server Error"
	name: "HttpErrorResponse"
	ok: false
	status: 500
	statusText: "Internal Server Error"
	url: "http://xxx.xxx.com:4200/marketplace-web/api/product/get-productAll/aa?page=1&size=5"
// get请求拼接参数
 return this.http.get(url, {params: {page: '1', size: '5'}})

树结构每次都调用,确实太浪费了,所以使用service-BehaviorSubject:

 ng g service core/category-tree


ng g c product/category-subtree
ng g c product/product-list-filter

问题小结:

  • 输入属性发生变化,如何监听???
    1.get和set
    2.生命周期钩子函数
    3.订阅啊

  • Set的时候,如果add和delete后,值会变化么?是不是跟对象一样,是引用类型?

  • ChangeDetectorRef和changeDetection: ChangeDetectionStrategy.OnPush,

开始home页面:

ng g c home/product-list
ng g c home/product-categories
ng g c home/publish-section
ng g c home/product-list-item

详情页面:

ng g c product/product-head


// 获取用户评论
public commentData:{total:number,data:[],iscomment:number}={
  total:0,data:[],iscomment:2,
}



flex布局的时候:
ul>li,li里面是文字:

注:
1.ul要flex-wrap换行
2.li要不缩,shrink:0;

input属性的时候,使用了get方法。

按钮的防重复点击:(跟搜索一样的)

public collectEmit$ = new Subject();

// 初始化这个
this.collectEmit$
  .pipe(
    debounceTime(300),
    tap(res=>{
      console.log("tap的res:",res);
    }),
    distinctUntilChanged(),
  ).subscribe(res=>{
    this.collect.emit(res);
})



// 调用函数:
this.collectEmit$.next(data);


注:因为有distinctUntilChanged,所以只有值变化后才可以触发事件。data改变属性也是可以监听到的。

rxjs-finalize:
描述:Call a function when observable completes or errors。
成功和失败都会执行 的函数。

购买一系列操作还没做!

轮播和用户评价:

ng g c product/product-screenshot
ng g c product/product-intro
ng g c product/product-other  
ng g c product/user-evaluate // 评价
ng g c product/user-evaluate-list   // 评价列表

set和get的使用:

正常:

@Input() data:any; // 评论列表


ngOnInit() {
  console.log(this.data); //  undefined
  setTimeout(()=>{
    console.log(this.data); // 正确的数据
  },1000)
}

ngAfterViewInit(){
  console.log("ngAfterViewInit:",this.data); // 也是获取不到数的。
}

get和set:

_data:any;

@Input()
set data(value){ // 设置
  console.log("value %C%C",value);
  if(!value) {
    this._data={total:0,data:[]};
  }
  this._data = value;
}

get data(){ // 取值
  return this._data;
}


// 其他值的使用:
get total(){
  // console.log('aaaa');
  return this.data&&this.data.total;
}
get commentList(){
  return this.data&&this.data.data;
}

管道:slice:eg:

 <li *ngFor="let i of collection | slice:1:3">{{i}}</li>
 
collection: string[] = ['a', 'b', 'c', 'd'];

注:看下管道那个,已经忘光了。

报错:eg:

ERROR Error: 
	ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
	Previous value: 'ngForOf: [object Object]'. Current value: 'ngForOf: [object Object],[object Object]'.

参考:
https://blog.youkuaiyun.com/qq_33242126/article/details/79734150
https://www.cnblogs.com/xudengwei/p/9214959.html
https://blog.youkuaiyun.com/friend_ship/article/details/81773057
案例分析:

<li class="mp-user-evaluate-list__item"
    *ngFor="let item of (commentList | slice:0:count)">
</li>


count:any=1;

ngAfterViewInit(){
  console.log("ngAfterViewInit:",this.data);
  this.count=2;
  // Promise.resolve().then(() => this.count = 2);
}

angular的动画:官网:https://angular.cn/guide/animations

angular获取dom元素:
参考:
https://blog.youkuaiyun.com/idomyway/article/details/83656366
https://blog.youkuaiyun.com/qq_28004379/article/details/80801378

获取元素的样式:

getComputedStyle(elDom, null)

生命周期钩子:
https://www.colabug.com/2645773.html

computedIntroHeight:浏览器大小变化,也会执行的。

文本是输入属性传递进来的,盒子的h在输入属性渲染后才能获取;那么h用什么事件监听?
ngAfterViewChecked,然后用this.cdRef.detectChanges(); (ChangeDetectorRef)强制刷新视图。

注:这个用法不太好,因为只要窗口大小有变化,就会执行;那么其他的操作,eg:NzNotificationService,弹框,也会执行,使用了ngAfterViewChecked的组件会重新渲染,效果有问题的。(鼠标移入NzNotificationService,页面h会变化的)

时间格式化:

npm install date-fns 

1.30.1和2.0.1版本的使用不一样了!
eg:年月日的格式化:

import { format, compareAsc } from 'date-fns'

format(new Date(2014, 1, 11), 'MM/dd/yyyy') // 2.x
format(new Date(2014, 1, 11), 'MM/DD/YYYY') // 1.x

文档:https://date-fns.org/

 ng g service  share/concat

新建模块和组件:文件名与文件夹名不一致:

ng g m carousel/mp-carousel --flat

ng g c carousel/mp-carousel --flat
 npm install hammerjs
 npm i ngx-image-gallery
 

ng-content 内容投影。

ngx-image-gallery:参数:

imageBorderRadius:'20px', // 图片的圆角
imageOffset: '40px', // add gap between image and it's container (default 20px)
showCloseControl: false, // 是否显示关闭按钮
showDeleteControl: false, // 是否显示删除按钮
showExtUrlControl: false,
imagePointer: true,
showImageTitle: true, // 是否显示描述
backdropColor: 'rgba(0, 0, 0, 0.5)', // 背景颜色
showThumbnails: true, // 是否显示缩略图
inline: true, // 弹框模式还是inline模式
showArrows: true, // 是否显示箭头
thumbnailSize:60, // 缩略图的大小。thumbnail:缩略图
reactToMouseWheel:true, // 是否鼠标滚动,好像方向是反着的!!!!
reactToKeyboard:false, // 键盘是否可以切换图片(弹框的时候,才可以使用键盘)

轮播图:

就是antd的轮播图源码!照着看一遍吧。
路径:/node_modules/ng-zorro-antd/fesm2015/ng-zorro-antd.js

引出的问题:
@HostBinding()和@HostListener():参考:
https://www.cnblogs.com/cme-kai/p/8352087.html
https://segmentfault.com/a/1190000008878888
https://blog.youkuaiyun.com/ligaoming_123/article/details/81531623

NgTemplateOutlet 参考:

https://segmentfault.com/a/1190000009530554
https://segmentfault.com/a/1190000015944548
ng-template, ng-container and ngTemplateOutlet:参考:
https://blog.youkuaiyun.com/m0_37529303/article/details/80690518
[https://blog.youkuaiyun.com/Create_mylife/article/details/85615585](https://blog.youkuaiyun.com
/Create_mylife/article/details/85615585)
https://www.jianshu.com/p/e5bed2678ab1

个人的博客内容:eg:https://www.cnblogs.com/cme-kai/p/8497146.html

标题SpringBoot智能在线预约挂号系统研究AI更换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景与意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究与应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则和常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计与管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全与数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计与实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现与测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试与分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化与改进根据测试结果对系统进行优化和改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值