Angular网络请求

更新日期: 2019-03-28阅读: 3.2k标签: 网络

angular网络请求是一个最常见的应用之一,下列我将以 ng-alain 项目为基础描述 Angular 网络请求。

注:示例中代码都以简化的形式出现。


写在前面

Angular发起一个请求再简单不过即使用 HttpClient 类的各种方法,然在开始之前我们应退一小步,先从如何构建一个 Restful api 开始,后端的API设计将很大程度决定前后端如何更优雅的开发有着非常大的关键性作用。


一、RESTful API 设计

私以为API的设计分为请求与输出两个部分。而连接二者是依靠URL,关于URL如何更合理的设计可以参考阮一峰-RESTful API 设计指南

这一部分要谈另一个可能大家容易忽略的细节,请求体与返回体规范。这一点淘宝开放平台是一个非常好的典范,例如所有异常返回体:

{
    "sub_msg":"非法参数",
    "code":50,
    "sub_code":"isv.invalid-parameter",
    "msg":"Remote service error"
}

所有这些规则可以由内部自行决议,再比如我们中后台经常使用的是一种方式,所有返回体不管成功与否都包含以下对象:

{
    "msg": "ok",
    "data": null
}

以 msg 来判断 ok 值表示成功,对于其他值表示允许直接显示给用户错误文本异常文本。

对于提交 POST 请求体的数据格式(content-type)主要两种比较常见:表单格式和JSON格式,二者也可能根据不同场景情况使用特别是文件上传动作;当然对于大部分场景而言 JSON 格式最优先的形式,不管你是使用 Angular 表单的html模板或响应式驱动表单都是直接跟JSON打交道。


二、请求流程

在 ng-alain 中,一个完整的 Angular 应用从前端 UI 交互到服务端处理流程是这样的:

1、首次启动 Angular 执行 APP_INITIALIZER;
2、UI 组件交互操作;
3、使用 HttpClient 发送请求;
4、触发用户认证拦截器 @delon/auth,统一加入 token 参数;

a、若未存在 `token` 或已过期中断后续请求,直接跳转至登录页;

5、触发默认拦截器,统一处理前缀等信息;
6、获取服务端返回;
7、触发默认拦截器,统一处理请求异常、业务异常等;
8、数据更新,并刷新 UI。

本文我们不介绍渲染方面,因此 2,6,8 三点将不做介绍。


1、APP_INITIALIZER

应用初始化是在应用启动过程中有且只执行一次,一般来讲我们需要在应用一启动时加载一些数据:应用信息、通用数据字典、用户数据等。

只需要向 APP_INITIALIZER 注册一个带有 Promise 返回值即可;例如:

{
  provide: APP_INITIALIZER,
  useValue: () => new Promise(() => {}),
  multi: true
}

正因为是一个 Promise 异步,我们就可以在这里利用 HttpClient 做网络请求,从而实现在 Angular 启动之前通过网络请求获取一个启用后一开始就需要的数据。

注:当然在这里发起的网络请求拦截器依然有效,若拦截器包含一些用户 Token 的有效性校验而导致跳转至登录页时,可能要小心处理了。

但不管如何最终你想启动 Angular 都必须确保 Promise 正确的调用 resolve()。


2、HttpClient

HttpClient 是 Angular 封装了一个简化的 API 来实现 HTTP 客户端功能,例如一个 get 请求:

constructor(http: HttpClient) {
  http.get('/user/1').subscribe((user) => {
    console.log(user);
  });
}

另一个 post 请求:

constructor(http: HttpClient) {
  http.post('/user/1', { a: 1 }).subscribe((user) => {
    console.log(user);
  });
}

所有请求类型返回的结果都是 Observable<any> 类型,意味着不管如果你都必须调用 subscribe 才会真正的发起请求。大多数情况下你可能会觉得很麻烦,但当你需要一些节流或数据转换时就显得 rxjs 的魅力,有关更多细节自行Google rxjs。


3、拦截器

拦截网络请求或响应,用于统一处理请求或响应结果数据。并且可以运用多个拦截器且按顺序执行,类似于 Node 中间件。

一个简单示例

只需要简单实现 HttpInterceptor 接口即可:

export class SimpleInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    const newReq = req.clone();
    return next.handle(newReq).pipe()
  }
}

拦截器返回的结果是一个 Observable 值,这意味着同一个拦截器代码包含着请求和响应两个部分的处理,所有在 Angular 拦截器里并没有明确区分请求和响应处理,这也是 rxjs 的魅力。

使用 req.clone() 克隆一些新的请求体,当然请求体包含着所有 HttpClient 发起数据及参数。例如给所有请求体的 headers 加入用户 Token 值。

const newReq = req.clone({
  setHeaders: { Authorization: `Bearer ${this.token}` },
});

当响应体网络状态码非 401 时,打算跳转至登录页,则:

return next.handle(newReq)
           .pipe(
             catchError(err => {
               if (err.status === 401) {
                 this.injector.get(Router).navigateByUrl('/login');
               }
             })
           )

最后,在模块里注册,若你希望在整个应用有效可以在根模块里注册:

{ provide: HTTP_INTERCEPTORS, useClass: SimpleInterceptor, multi: true },

拦截器顺序

拦截器可以注册在任何模块里,而一个网络请求所经过拦截器从模块向上查找至根模块,若一个模块包含多个拦截器时按代码顺序执行。


三、ng-alain 请求处理

ng-alain 默认装载了两个拦截器:@delon/auth 用户认证和默认拦截器。


1、用户认证

本身是为 ng-alain 脚手架提供的一个 用户认证模块,包含主流的  JWT(Json Web Token)和一个相对通用 Simple Web Token,而其核心是对认证过程进一步处理。而通常其核心在于用户 Token 的获取、使用环节。

同时,@delon/auth 并不会关心用户界面是怎么样,只需要当登录成功后将后端返回的数据交给 ITokenService,它会帮你存储在 localStorage(默认) 当中;当发起一个网络请求时,它会在自动在 header(默认) 当中加入相应的 token 信息。

因此,@delon/auth 不限于 ng-alain 脚手架,任何 Angular 项目都可以使用它。

默认装载了 SimpleInterceptor 拦截器,意味者一开始使用 ng-alain 为什么会无缘无故无法正确请求,而是直接抛出异常。

ng-alain 是一个完整且可直接运用项目的脚手架,因此所有默认配置都尽可能生产环境中代码,其实理解这一点很重要,因为大部分一开始总希望使用一个 Hello World 请求来决定是不是真的可以使用。

有关更多细节请参考文档


2、默认拦截器

DefaultInterceptor 拦截器,它是一个默认拦截器示例代码,包含请求体和响应体的处理。

例如当我们统一响应体如下:

{
    "msg": "ok",
    "data": { id: 1, name: "cipchk" }
}

对于 subscribe 结果来说只需要关心 data 部分,因此可以在拦截器进一步转化:

return of(new HttpResponse(Object.assign(event, { body: body.data })));

使在订阅结果时给保持一个最简单有效数据:

http.get('/user/1').subscribe(user => console.log(user));
// output: { id: 1, name: "cipchk" }

更多做法,例如:统一处理异常消息等,可以参考 default.interceptor.ts 的写法。


总结

Angular 网络请求看起来就像一个简化版的 Web 服务,发起的请求经过一道道关卡后,接收响应结果时又经过原先经过的一道道关卡最后交给用户。

当然这一切的本质还是 rxjs 带来的。曾经有人提过为什么 ng-alain 不采用 Redux 形式,但我实在找不到有什么理由要这么做,大部分中后台都以网络请求来完成大部分事务,而 Angular 网络请求又那么清晰。


链接: https://fly63.com/article/detial/2585

浅谈对soket的理解

网络上的两个程序通过一个双向的通信链实现数据的交换,这个链接的一端就成为Socket,它是进程通信的一种,即调用这个网络库的api函数实现分布在不同主机相关进程之间的数据交换

kubernetes之Flannel网络插件部署

Kubernetes系统上Pod网络的实现依赖于第三方插件,而Flannel是由CoreOS主推的目前比较主流的容器网络解决方案,CNI插件有两种功能:网络配置和网络策略,由于flannel比较简单,并不支持网络策略

JS 测试网络速度与网络延迟

通过js加载一张1x1的极小图片,测试出图片加载的所用的时长。如果换一个几百KB的图片,则可心用来计算下载网速 ,第一次加载图像时,它将比后续加载花费更长的时间,即使我们确保图像没有被缓存。

2019最新网络赚钱方法有哪些?推荐几种靠谱赚钱方式!

2019年已经是互联网发展的成熟期了,随着网络的不断发展,以及手机应用的普及,几乎人人都已经会使用网络工具。但是又有多少人知道网络赚钱这个小众的赚钱方式呢?

全面分析前端的网络请求方式

大多数情况下,在前端发起一个网络请求我们只需关注下面几点:传入基本参数(url,请求方式),请求参数、请求参数类型,设置请求获取响应的方式

由Web Beacon-网络臭虫引发的思考

为何在百度搜索之后,一些网站总能够推荐我刚刚搜索过的东西?百度会记录你的搜索信息,同时会在你本地保存一个标识本地的cookie,而当你打开第三方网站时,第三方网站嵌入了百度广告的JS代码

Deepfake_深度神经网络换脸

Deepfake从技术的角度而言,这是深度图像生成模型的一次非常成功的应用,这两年虽然涌现出了很多图像生成模型方面的论文,但大都是能算是Demo,没有多少的实用价值,除非在特定领域(比如医学上)

从狭义SDN到广义SDN,网络自动化趋势下的SDN

SDN的概念主要体现的是技术架构视角,强调的是实现网络设备的软件硬件解耦、网络系统的控制面与转发面解耦,以及整体全面的可编程性。SDN的优势在于它是基于系统全局信息进行网络转发等的策略决策的

计算机网络常见问题

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值

前端网络监控与断网重链

最近在做大屏数据可视化项目得时候,在思考项目交付和运行情况得时候,考虑到了需要在公司大屏显示器上面展示,突然想到了项目可能面临断网及其网速慢得情况下得一下展示问题,因此作为专栏进行这两个问题得讲解

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!