概述

在这个教程中,我们将探讨如何在Postman中使用x-www-form-urlencoded格式发送数组作为数据的一部分。

W3C委员会(https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)定义了多种网络层数据发送格式,包括`form-data`、`raw`和`x-www-form-urlencoded`。我们通常默认使用后者来发送数据。

2. x-www-form-urlencoded

这种格式描述的是以HTTP消息体中的一块形式发送的表单数据。它将编码后的数据集发送到服务器进行提交。编码后的数据采用键值对的形式。服务器必须支持此内容类型。

使用此类内容类型的表单提交遵循以下编码模式:

  • 控件名称和值会被转义。
  • 多个值由逗号(,)分隔。
  • 加号(+)会替换所有空格字符。
  • 保留字符应遵循RFC 17.38的记法。
  • 所有非字母数字字符使用百分比编码。
  • 键与值之间用等号(=)分隔,而键值对之间用&(&)分隔。

此外,数据长度未指定。然而,使用x-www-form-urlencoded数据类型有数据大小限制,因此媒体服务器会拒绝超出配置中指定大小的请求。

当发送二进制数据或包含非字母数字字符的值时,效率会降低。包含非字母数字字符的键和值会进行百分比编码(也称为URL编码),因此这种类型不适合二进制数据。因此,我们应该考虑使用form-data内容类型。

此外,它不适用于编码文件。它只能编码URL参数或请求体内的数据。

3. 发送数组

要在Postman中使用x-www-form-urlencoded类型,我们需要在请求的“主体”标签页中选择具有相同名称的单选按钮。

如前所述,请求由键值对组成。Postman会在发送到服务器之前对数据进行编码。同时,它会编码键和值。

现在,让我们看看如何在Postman中发送数组。

3.1. 发送简单的数组对象

我们首先展示如何发送一个包含简单类型(如字符串)的简单数组对象。

首先,创建一个名为Student的类,其中包含一个数组实例变量:

class StudentSimple {

   private String firstName;
   private String lastName;
   private String[] courses;

   // getters and setters
}

接下来,定义一个控制器类,暴露REST端点:

@PostMapping(
  path = "/simple", 
  consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity<StudentSimple> createStudentSimple(StudentSimple student) {
    return ResponseEntity.ok(student);
}

当我们使用@Consumes注解时,需要将x-www-form-urlencoded指定为客户可以从控制器接收的媒体类型。否则,我们将收到“415 unsupported media type”错误。此外,由于@RequestBody注解不支持x-www-form-urlencoded内容类型,我们需要移除它。

最后,在Postman中创建一个请求。最简单的方法是使用逗号符号(,)分隔值:

然而,如果值本身包含逗号,这种方法可能会出现问题。我们可以通过分别设置每个值来解决这个问题。为了将元素添加到courses数组中,我们需要使用相同的键提供键值对:

数组元素的顺序将遵循请求中提供的顺序。

方括号是可选的。另一方面,如果我们想在数组的特定索引处添加元素,可以在方括号中指定索引:

我们可以使用cURL请求测试我们的应用程序:

curl -X POST \
  http://localhost:8080/students/simple \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'firstName=Jane&lastName=Doe&
        courses[2]=Programming+in+Java&
        courses[1]=Data+Structures&
        courses[0]=Linux+Basics'

3.2. 发送复杂数组对象

现在来看看如何发送包含复杂对象的数组。

首先,定义一个表示单个课程的Course类:

class Course {

    private String name;
    private int hours;
    
    // getters and setters
}

接着,创建一个表示学生的类:

class StudentComplex {

    private String firstName;
    private String lastName;
    private Course[] courses;

    // getters and setters
}

在控制器类中添加一个新的端点:

@PostMapping(
  path = "/complex",
  consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseEntity<StudentComplex> createStudentComplex(StudentComplex student) {
    return ResponseEntity.ok(student);
}

最后,在Postman中创建一个请求。与前一个示例一样,为了向数组添加元素,我们需要使用相同的键提供键值对:

这里,带有索引的方括号是必需的。要设置每个实例变量的值,我们需要使用点(.)操作符后跟变量名。

再次,可以使用cURL请求测试端点:

curl -X POST \
  http://localhost:8080/students/complex \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'firstName=Jane&lastName=Doe&
        courses[0].name=Programming+in+Java&
        courses[0].hours=40&
        courses[1].name=Data+Structures&
        courses[1].hours=35'

4. 总结

在这篇文章中,我们学习了如何在服务器端正确设置Content-Type以避免“Unsupported Media Type”错误。此外,我们解释了如何在Postman中使用x-www-form-urlencoded内容类型发送简单的和复杂的数组。

如往常一样,所有的代码片段可在GitHub上找到:https://github.com/eugenp/tutorials/tree/master/spring-web-modules/spring-rest-http-3