REST API中的HTTP PUT与POST

2023/05/19

1. 概述

在本教程中,我们将研究我们在REST架构中经常使用的两个重要的HTTP方法,PUT和POST。众所周知,开发人员有时在设计RESTful Web服务时难以在这两种方法之间做出选择。因此,我们将通过在Spring Boot中简单实现RESTful应用程序来解决这个问题。

2. PUT与POST困境

在典型的REST架构中,客户端以HTTP方法的形式向服务器发送请求,以创建、检索、修改或销毁资源。虽然我们可以同时使用PUT和POST来创建资源,但它们在预期应用方面存在显着差异。

根据RFC 2616标准,应使用POST方法请求服务器接受封闭实体作为Request-URI标识的现有资源的从属。这意味着POST方法调用将在资源集合下创建一个子资源。

相反,应该使用PUT方法来请求服务器在提供的Request-URI下存储封闭的实体。如果Request-URI指向服务器上的现有资源,则提供的实体将被视为现有资源的修改版本。因此,PUT方法调用将创建新资源或更新现有资源。

这些方法之间的另一个重要区别是PUT是一种幂等方法,而POST不是。例如,多次调用PUT方法将创建或更新相同的资源。相比之下,多个POST请求会导致多次创建同一个资源。

3. 示例应用

为了演示PUT和POST之间的区别,我们将使用Spring Boot创建一个简单的RESTful Web应用程序。该应用程序将存储人员的姓名和地址。

3.1 Maven依赖项

首先,我们需要在pom.xml文件中包含Spring Web、Spring Data JPA和内存中的H2数据库的依赖项:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

3.2 域实体和Repository接口

让我们先从创建域对象开始。对于地址簿,我们将定义一个名为Address的实体类,我们将使用它来存储个人的地址信息。为了简单起见,我们将为地址实体使用三个字段,名称、城市和邮政编码:

@Entity
public class Address {

    private @Id @GeneratedValue Long id;
    private String name;
    private String city;
    private String postalCode;

    // constructors, getters, and setters
}

下一步是访问数据库中的数据。为简单起见,我们将利用Spring Data JPA的JpaRepository,这将允许我们在不编写任何额外代码的情况下对数据执行CRUD功能:

public interface AddressRepository extends JpaRepository<Address, Long> {
}

3.3 REST控制器

最后,我们需要为我们的应用程序定义API端点,我们将创建一个RestController,它将使用来自客户端的HTTP请求并发回适当的响应。

在这里,我们将定义一个@PostMapping用于创建新地址并将它们存储在数据库中,以及一个@PutMapping用于根据请求URI更新地址簿的内容。如果未找到URI,它将创建一个新地址并将其存储在数据库中:

@RestController
public class AddressController {

    private final AddressRepository repository;

    AddressController(AddressRepository repository) {
        this.repository = repository;
    }

    @PostMapping("/addresses")
    Address createNewAddress(@RequestBody Address newAddress) {
        return repository.save(newAddress);
    }

    @PutMapping("/addresses/{id}")
    Address replaceEmployee(@RequestBody Address newAddress, @PathVariable Long id) {

        return repository.findById(id)
              .map(address -> {
                  address.setCity(newAddress.getCity());
                  address.setPin(newAddress.getPostalCode());
                  return repository.save(address);
              })
              .orElseGet(() -> {
                  return repository.save(newAddress);
              });
    }
    // additional methods omitted
}

3.4 cURL请求

现在我们可以通过使用cURL向我们的服务器发送示例HTTP请求来测试我们开发的应用程序。

为了创建新地址,我们将以JSON格式封装数据并通过POST请求发送:

curl -X POST --header 'Content-Type: application/json' \
    -d '{ "name": "John Doe", "city": "Berlin", "postalCode": "10585" }' \ 
    http://localhost:8080/addresses

现在让我们更新我们创建的地址的内容。我们将使用URL中该地址的ID发送PUT请求。在此示例中,我们将更新刚创建的地址的城市和邮政编码部分。我们假设它是用id=1保存的:

curl -X PUT --header 'Content-Type: application/json' \
  -d '{ "name": "John Doe", "city": "Frankfurt", "postalCode": "60306" }' \ 
  http://localhost:8080/addresses/1

4. 总结

在本文中,我们讨论了HTTP方法PUT和POST之间的概念差异。此外,我们还了解了如何使用用于开发RESTful应用程序的Spring Boot框架来实现这些方法。

总之,我们应该使用POST方法创建新资源,使用PUT方法更新现有资源。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章