MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Angular HTTP请求的请求方法与参数传递

2022-08-242.0k 阅读

Angular HTTP 请求概述

在 Angular 应用开发中,与后端服务器进行数据交互是常见需求。Angular 通过 @angular/common/http 模块提供了强大的 HTTP 客户端功能,使得发起 HTTP 请求变得相对简单。HTTP 协议定义了多种请求方法,每种方法都有其特定用途,同时在请求过程中,参数传递也是关键环节,它决定了如何向服务器传达数据。

HTTP 请求方法

  1. GET 请求
    • 用途:GET 请求主要用于从服务器获取数据。它将参数附加在 URL 后面,以键值对形式呈现,适合获取资源列表、查询数据等场景。例如,从服务器获取一篇博客文章列表,或者根据特定条件查询数据库记录。
    • 特点:由于参数暴露在 URL 中,不太适合传递敏感信息。同时,GET 请求有 URL 长度限制,不同浏览器和服务器对此限制不同,但一般来说长度较短。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-get-example',
  templateUrl: './get - example.component.html'
})
export class GetExampleComponent {
  constructor(private http: HttpClient) {}

  getData() {
    const url = 'https://api.example.com/posts';
    this.http.get(url).subscribe((response) => {
      console.log(response);
    });
  }
}

在上述代码中,通过 HttpClientget 方法向指定 URL 发起 GET 请求,获取博客文章列表数据,并在控制台打印响应结果。

  1. POST 请求
    • 用途:POST 请求用于向服务器提交数据,通常用于创建新资源。比如用户注册、提交表单数据等场景。它将数据放在请求体中发送,而非像 GET 那样放在 URL 中。
    • 特点:适合传递大量数据,且数据相对安全,因为不在 URL 中暴露。但 POST 请求相对 GET 请求来说,性能略低,因为请求体解析等操作相对复杂。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - post - example',
  templateUrl: './post - example.component.html'
})
export class PostExampleComponent {
  constructor(private http: HttpClient) {}

  postData() {
    const url = 'https://api.example.com/users';
    const userData = {
      username: 'testUser',
      password: 'testPassword'
    };
    this.http.post(url, userData).subscribe((response) => {
      console.log(response);
    });
  }
}

这里向 /users 端点发起 POST 请求,传递用户注册信息,服务器接收到这些数据后可创建新用户记录。

  1. PUT 请求
    • 用途:PUT 请求用于更新服务器上的资源。它通常用于完全替换资源的情况,即客户端提供完整的资源数据,服务器用这些数据覆盖原有的资源。比如更新用户的完整信息,包括用户名、邮箱、地址等所有字段。
    • 特点:要求客户端提供完整的资源数据,如果只想更新部分字段,可能不太适用,此时 PATCH 请求更合适。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - put - example',
  templateUrl: './put - example.component.html'
})
export class PutExampleComponent {
  constructor(private http: HttpClient) {}

  putData() {
    const url = 'https://api.example.com/users/1';
    const updatedUserData = {
      username: 'updatedUser',
      password: 'updatedPassword',
      email: 'updated@example.com'
    };
    this.http.put(url, updatedUserData).subscribe((response) => {
      console.log(response);
    });
  }
}

此代码向 users/1 端点发起 PUT 请求,更新 ID 为 1 的用户的所有信息。

  1. PATCH 请求
    • 用途:PATCH 请求同样用于更新资源,但与 PUT 不同,它只更新客户端提供的部分字段。适用于只想修改资源部分属性的场景,比如只修改用户的邮箱地址,而不改变其他信息。
    • 特点:更灵活,减少不必要的数据传输。但服务器端需要支持部分更新逻辑。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - patch - example',
  templateUrl: './patch - example.component.html'
})
export class PatchExampleComponent {
  constructor(private http: HttpClient) {}

  patchData() {
    const url = 'https://api.example.com/users/1';
    const partialUserData = {
      email: 'newemail@example.com'
    };
    this.http.patch(url, partialUserData).subscribe((response) => {
      console.log(response);
    });
  }
}

这里向 users/1 发起 PATCH 请求,仅更新用户的邮箱字段。

  1. DELETE 请求
    • 用途:DELETE 请求用于从服务器删除资源。比如删除一篇文章、一个用户等。
    • 特点:操作不可逆,使用时需谨慎确认用户意图。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - delete - example',
  templateUrl: './delete - example.component.html'
})
export class DeleteExampleComponent {
  constructor(private http: HttpClient) {}

  deleteData() {
    const url = 'https://api.example.com/posts/1';
    this.http.delete(url).subscribe((response) => {
      console.log(response);
    });
  }
}

此代码向 posts/1 端点发起 DELETE 请求,删除 ID 为 1 的文章。

参数传递

  1. URL 参数(查询字符串参数)
    • GET 请求中的使用:在 GET 请求中,URL 参数是常用的传递方式。通过在 URL 后面添加 ? 符号,然后以 key=value 的形式列出参数,多个参数之间用 & 分隔。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - query - params - example',
  templateUrl: './query - params - example.component.html'
})
export class QueryParamsExampleComponent {
  constructor(private http: HttpClient) {}

  getWithParams() {
    const url = 'https://api.example.com/posts';
    const params = {
      category: 'tech',
      limit: 10
    };
    this.http.get(url, { params }).subscribe((response) => {
      console.log(response);
    });
  }
}

上述代码中,categorylimit 作为 URL 参数附加在请求 URL 上,服务器可根据这些参数返回特定分类且数量限制为 10 的文章列表。

  1. 请求体参数
    • POST、PUT、PATCH 请求中的使用:这些请求通常将参数放在请求体中。请求体数据的格式常见为 JSON,因为它简单易读且被广泛支持。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - request - body - example',
  templateUrl: './request - body - example.component.html'
})
export class RequestBodyExampleComponent {
  constructor(private http: HttpClient) {}

  postWithBody() {
    const url = 'https://api.example.com/orders';
    const orderData = {
      product: 'laptop',
      quantity: 2,
      price: 1000
    };
    this.http.post(url, orderData).subscribe((response) => {
      console.log(response);
    });
  }
}

这里 orderData 作为请求体参数通过 POST 请求发送到 /orders 端点,服务器可据此创建新订单记录。

  1. 路径参数
    • 用途:路径参数嵌入在 URL 路径中,用于标识特定资源。比如在获取单个用户信息时,URL 中包含用户 ID。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - path - params - example',
  templateUrl: './path - params - example.component.html'
})
export class PathParamsExampleComponent {
  constructor(private http: HttpClient) {}

  getSingleUser() {
    const userId = 1;
    const url = `https://api.example.com/users/${userId}`;
    this.http.get(url).subscribe((response) => {
      console.log(response);
    });
  }
}

此代码中,userId 作为路径参数嵌入 URL,用于获取 ID 为 1 的用户信息。

处理复杂参数传递

  1. 嵌套对象与数组参数
    • 请求体中的嵌套结构:当传递复杂数据结构时,如包含嵌套对象或数组的数据。例如,一个订单可能包含多个商品项,每个商品项又有自己的属性。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - nested - params - example',
  templateUrl: './nested - params - example.component.html'
})
export class NestedParamsExampleComponent {
  constructor(private http: HttpClient) {}

  postNestedData() {
    const url = 'https://api.example.com/orders';
    const orderData = {
      orderId: 1,
      customer: {
        name: 'John Doe',
        email: 'johndoe@example.com'
      },
      items: [
        {
          product: 'book',
          quantity: 3,
          price: 20
        },
        {
          product: 'pen',
          quantity: 5,
          price: 5
        }
      ]
    };
    this.http.post(url, orderData).subscribe((response) => {
      console.log(response);
    });
  }
}

在这个例子中,orderData 包含嵌套的 customer 对象和 items 数组,作为请求体参数发送,服务器可据此处理复杂订单信息。

  1. 序列化与反序列化
    • 序列化:当传递复杂数据结构时,需要确保数据以合适的格式发送到服务器。在 Angular 中,默认情况下,HttpClient 会将 JavaScript 对象序列化为 JSON 格式发送。但在某些情况下,可能需要自定义序列化方式,比如将日期对象格式化为特定字符串。
    • 反序列化:从服务器接收到响应后,可能需要将 JSON 数据反序列化为 TypeScript 对象,以便在应用中更好地处理。可以通过定义接口或类,并使用 map 操作符来实现。
    • 代码示例(反序列化)
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

interface User {
  id: number;
  username: string;
  email: string;
}

@Component({
  selector: 'app - deserialization - example',
  templateUrl: './deserialization - example.component.html'
})
export class DeserializationExampleComponent {
  constructor(private http: HttpClient) {}

  getUser() {
    const url = 'https://api.example.com/users/1';
    this.http.get(url).pipe(
      map((response: any) => {
        const user: User = {
          id: response.id,
          username: response.username,
          email: response.email
        };
        return user;
      })
    ).subscribe((user) => {
      console.log(user);
    });
  }
}

此代码从服务器获取用户数据,通过 map 操作符将响应数据反序列化为 User 接口定义的对象,便于后续处理。

处理参数编码与特殊字符

  1. URL 编码
    • 原理:由于 URL 对字符有一定限制,某些特殊字符(如空格、&、? 等)需要进行编码。在 Angular 中,HttpClient 会自动对 URL 参数进行编码。但在手动构建 URL 时,需注意使用 encodeURIComponent 函数对特殊字符进行编码。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - url - encoding - example',
  templateUrl: './url - encoding - example.component.html'
})
export class UrlEncodingExampleComponent {
  constructor(private http: HttpClient) {}

  getWithEncodedParams() {
    const searchTerm = 'hello world';
    const encodedSearchTerm = encodeURIComponent(searchTerm);
    const url = `https://api.example.com/search?term=${encodedSearchTerm}`;
    this.http.get(url).subscribe((response) => {
      console.log(response);
    });
  }
}

这里将包含空格的搜索词 hello world 进行 URL 编码,确保请求 URL 正确。

  1. 请求体编码
    • JSON 编码:对于请求体中的 JSON 数据,HttpClient 会自动将 JavaScript 对象转换为 JSON 字符串并设置 Content - Typeapplication/json。但如果需要发送其他格式的数据,如 application/x - www - form - urlencoded,则需要手动进行编码。
    • 代码示例(发送 application/x - www - form - urlencoded 数据)
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { URLSearchParams } from '@angular/http';

@Component({
  selector: 'app - form - urlencoded - example',
  templateUrl: './form - urlencoded - example.component.html'
})
export class FormUrlencodedExampleComponent {
  constructor(private http: HttpClient) {}

  postFormUrlencodedData() {
    const url = 'https://api.example.com/login';
    const params = new URLSearchParams();
    params.set('username', 'testUser');
    params.set('password', 'testPassword');
    const headers = { 'Content - Type': 'application/x - www - form - urlencoded' };
    this.http.post(url, params.toString(), { headers }).subscribe((response) => {
      console.log(response);
    });
  }
}

此代码通过 URLSearchParams 将数据格式化为 application/x - www - form - urlencoded 形式,并设置相应的 Content - Type 头进行 POST 请求。

处理请求头与参数相关配置

  1. 设置请求头
    • 用途:请求头可以传递额外信息,如认证令牌、数据格式说明等。在 Angular 中,可通过 HttpHeaders 对象来设置请求头。
    • 代码示例
import { Component } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

@Component({
  selector: 'app - headers - example',
  templateUrl: './headers - example.component.html'
})
export class HeadersExampleComponent {
  constructor(private http: HttpClient) {}

  getWithHeaders() {
    const url = 'https://api.example.com/protected - data';
    const headers = new HttpHeaders({
      'Authorization': 'Bearer your - token - here',
      'Content - Type': 'application/json'
    });
    this.http.get(url, { headers }).subscribe((response) => {
      console.log(response);
    });
  }
}

这里设置了 Authorization 头用于认证和 Content - Type 头说明数据格式,以便获取受保护的数据。

  1. 参数配置选项
    • 其他配置:除了设置参数和请求头,HttpClient 的请求方法还支持其他配置选项,如 observe 用于指定观察响应的方式(如仅观察响应体或完整响应),responseType 用于指定响应数据类型(如 jsontextblob 等)。
    • 代码示例(设置 observe 和 responseType)
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - config - example',
  templateUrl: './config - example.component.html'
})
export class ConfigExampleComponent {
  constructor(private http: HttpClient) {}

  getWithConfig() {
    const url = 'https://api.example.com/image';
    this.http.get(url, {
      observe: 'body',
      responseType: 'blob'
    }).subscribe((response: Blob) => {
      const objectURL = URL.createObjectURL(response);
      const img = new Image();
      img.src = objectURL;
      document.body.appendChild(img);
    });
  }
}

此代码设置 observebody 仅观察响应体,responseTypeblob 以获取图片的二进制大对象,然后创建图片元素并显示在页面上。

通过深入理解 Angular HTTP 请求的各种请求方法及其参数传递方式,开发者能够更加高效地构建与后端服务器进行数据交互的 Angular 应用,确保数据传输的准确性、安全性和高效性。无论是简单的数据获取还是复杂的业务逻辑交互,合理运用这些知识都能极大提升应用的质量和用户体验。在实际开发中,还需结合具体业务需求,灵活运用不同的请求方法和参数传递技巧,同时注意处理可能出现的错误情况,以打造健壮可靠的前端应用。

此外,在处理复杂业务场景时,可能会遇到多个请求之间的依赖关系,比如先获取用户信息,再根据用户信息获取其相关订单数据。这时可以使用 RxJS 的操作符(如 switchMapconcatMap 等)来管理这些异步请求的顺序和依赖。例如:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map, switchMap } from 'rxjs/operators';

interface User {
  id: number;
  username: string;
}

interface Order {
  id: number;
  userId: number;
  orderDetails: string;
}

@Component({
  selector: 'app - dependent - requests - example',
  templateUrl: './dependent - requests - example.component.html'
})
export class DependentRequestsExampleComponent {
  constructor(private http: HttpClient) {}

  getUserAndOrders() {
    const userUrl = 'https://api.example.com/users/1';
    const orderUrl = 'https://api.example.com/orders';
    this.http.get<User>(userUrl).pipe(
      switchMap((user) => {
        return this.http.get<Order[]>(`${orderUrl}?userId=${user.id}`);
      })
    ).subscribe((orders) => {
      console.log(orders);
    });
  }
}

在上述代码中,首先通过 GET 请求获取用户信息,然后使用 switchMap 操作符根据用户 ID 发起第二个 GET 请求获取该用户的订单数据。这样就巧妙地处理了两个请求之间的依赖关系,确保在获取到用户信息后再请求相关订单数据。

在处理参数传递时,还需要考虑数据的验证和安全性。对于来自用户输入的参数,必须进行严格的验证,防止恶意数据注入。例如,在使用 URL 参数进行数据库查询时,如果不进行验证,攻击者可能通过构造恶意 URL 来执行非法的数据库操作。可以在服务端和客户端都进行验证,在客户端可以使用正则表达式等方式对输入参数进行格式验证。比如验证邮箱格式:

function validateEmail(email: string): boolean {
  const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0 - 9]{1,3}\.[0 - 9]{1,3}\.[0 - 9]{1,3}\.[0 - 9]{1,3}\])|(([a-zA - Z\-0 - 9]+\.)+[a-zA - Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
}

然后在参数传递前调用此函数进行验证:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app - email - validation - example',
  templateUrl: './email - validation - example.component.html'
})
export class EmailValidationExampleComponent {
  constructor(private http: HttpClient) {}

  sendEmailData() {
    const email = 'test@example.com';
    if (validateEmail(email)) {
      const url = 'https://api.example.com/send - email';
      const data = { email };
      this.http.post(url, data).subscribe((response) => {
        console.log(response);
      });
    } else {
      console.error('Invalid email');
    }
  }
}

这样可以确保传递的邮箱参数格式正确,提高应用的安全性。

同时,在处理请求方法和参数传递时,性能也是一个重要考虑因素。对于频繁的 GET 请求,可以考虑使用缓存机制来减少服务器负载和提高响应速度。在 Angular 中,可以通过 RxJS 的 shareReplay 操作符来实现简单的缓存。例如:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { shareReplay } from 'rxjs/operators';

@Component({
  selector: 'app - cache - example',
  templateUrl: './cache - example.component.html'
})
export class CacheExampleComponent {
  private data$;
  constructor(private http: HttpClient) {}

  getData() {
    if (!this.data$) {
      const url = 'https://api.example.com/data';
      this.data$ = this.http.get(url).pipe(
        shareReplay(1)
      );
    }
    this.data$.subscribe((response) => {
      console.log(response);
    });
  }
}

在上述代码中,shareReplay(1) 会缓存最新的一次请求结果,当再次调用 getData 方法时,如果数据已经缓存,则直接使用缓存数据,而不会再次发起 HTTP 请求,从而提高了性能。

另外,在实际项目中,可能会遇到不同环境(开发、测试、生产)下服务器 URL 不同的情况。为了方便管理,可以使用 Angular 的环境配置文件。在 environments/environment.tsenvironments/environment.prod.ts 中分别定义不同环境下的服务器 URL,然后在服务中注入相应的配置。例如:

// environments/environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000/api'
};

// environments/environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.example.com'
};

// some - service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class SomeService {
  constructor(private http: HttpClient) {}

  getData() {
    const url = `${environment.apiUrl}/data`;
    return this.http.get(url);
  }
}

这样在不同环境下部署应用时,只需要切换环境配置文件,而无需在代码中大量修改服务器 URL,提高了代码的可维护性。

总之,Angular HTTP 请求的请求方法与参数传递涉及多个方面的知识和技巧,从基本的请求方法选择到复杂的数据结构传递,从参数验证到性能优化和环境配置,每个环节都对构建高质量的前端应用至关重要。开发者需要不断实践和深入理解这些内容,以应对各种实际开发场景。