从前往后—我的数据怎么传给后端啊

宋正兵 on 2020-11-03

前端通过HTTP请求发送数据给后端

客户端想要提交HTTP请求给Web服务器,通常都需要带有参数,包括:

  • URL:页面地址
  • METHOD:页面的提交方法,GET、POST等
  • Content-Type:HTTP请求提交的内容类型。一般只有post提交时才需要设置该属性
  • Body:存储POST的参数和参数数据

QGYHF83kTVIB9Lz.png

根据HTTP的请求方法对应的数据传输能力,把HTTP请求分为Url类请求和Body请求:

  • Url类请求:包括但不限于GET、HEAD、OPTIONS、TRACE等请求方法;
  • Body类请求:包括但不限于POST、PUSH、PATCH、DELETE等请求方法;

URL类请求释义

对于Url类请求,客户端是不能通过body写出数据的,服务端拿到的body是空的。因此一般情况下Url类的请求想要提交参数,就把参数跟在url后边,url一般是指向资源的,后面跟的参数更多的是一种条件和要求。

vHj867wQxV1Ahg5.png

我们把参数的这一段整体叫做Query,把它们拆开后组成键值对的形式又叫做Parameters,大多数情况下一个Key对应一个Value,当然是允许一个Key对应多个Values的。

Body类请求释义

对于Body类请求,客户端可以通过body写出数据,服务端可以通过body接收数据。也正因此Body类请求能上传到服务端的数据比Url类请求的大得多。

Body类请求除了可以把参数放到Url中,也可以通过body发送数据。

例如当Content-Type是 application/x-www-form-urlencoded 时,客户端可以通过body发送键值对数据,也可以通过url传参数,例如 key1=value1&key2=value2

例如当Content-Type是 application/json时,客户端可以通过body发送json字符串,如果是 application/xml 时可以发送xml字符串;

例如当Content-Type是 application/octet-stream 时,客户端可以通过body发送Binary数据,例如文件或者任何能转成流的数据;

例如当Content-Type是 multipart/form-data 时,客户端可以通过body发送一个表单。

注:表单是有格式的,不像json和xml格式,json和xml的格式是字符串排版格式,而表单的格式里面既有字符串又有换行和Binary。

前端HTTP请求实例

在这里仅针对Url类请求发送数据和Body类请求通过body发送数据做演示。后端在得到前端传递的数据后会再每个参数后面添加请求类型的名称,再返回给客户端。

Url类请求发送数据——url和参数拼接

以GET请求为例,发送用户的登录信息username和password给后端。

因为对于Url类请求,客户端不能通过body写出数据,所以我们需要把url和参数进行拼接,代码如下:

1
2
3
4
5
6
7
8
9
10
11
$(document).ready(function () {
$("button").click(function () {
// get请求
$.ajax({
url: "/login?username=" + $("#username").val() + "&password=" + $("#password").val(),
success: function (data) {
console.log(data);
}
})
})
})

GET请求报文:

58weCPzTStVXUc2.png

后端在接收到前端的GET请求之后,会在username和password参数后面添加字符串 --get,请求成功之后,在控制台打印返回的数据。

YWDVyXHpE5MP4mt.png

Body类请求发送数据——指定为application/json格式,放在body中

一般而言,对于Body类请求都习惯把数据存放到body中,大部分是以json格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 将表单的数据进行封装成JavaScript值,再转换为json字符串
function formToJsonObject(form) {
var a,o,h,i,e;
a = form.serializeArray();
o={};
h=o.hasOwnProperty;
for(i=0;i<a.length;i++){
e=a[i];
if(!h.call(o,e.name)){
o[e.name]=e.value;
}
}
return JSON.stringify(o);
}

$(document).ready(function () {
$("button").click(function () {
// post请求
$.ajax({
url: "/login",
type: "POST",
contentType: "application/json;charset=utf-8",
data: formToJsonObject($("#loginForm")),
success: function (data) {
console.log(data);
}
})
})
})

POST请求报文:

jvwDC3IPOYmhrWU.png

后端在接收到前端的POST请求之后,会在username和password参数后面添加字符串 --post,请求成功之后,在控制台打印返回的数据。

FU1wJjIX2RuyNso.png

后端接收HTTP请求实例

在整个实例中,我们都添加@ResponseBody注解,将java对象转为json格式的数据返回。

接收Url请求的数据

我们以前端HTTP请求的Url类请求实例为例,url为 http://localhost:8080/login?username=root&password=123456,传递的参数在query字段为 username=root&password=123456

我们已知客户端的请求类型有以下几种接收方式:

1)直接获取基本的数据类型

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。

1
2
3
4
5
6
7
8
9
10
@GetMapping("login")
@ResponseBody
public User getLogin(String username, String password) {
System.out.println("get");
System.out.println("username=" + username + "、password=" + password);
User user = new User();
user.setUsername(username + "--get");
user.setPassword(password + "--get");
return user;
}

2)获得POJO类型参数

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。

1
2
3
4
5
6
7
8
9
@GetMapping("login")
@ResponseBody
public User getLogin(User user) {
System.out.println("get");
System.out.println(user.toString());
user.setUsername(user.getUsername()+"--get");
user.setPassword(user.getPassword()+"--get");
return user;
}

接收Body类请求的数据

我们以前端HTTP请求的Body类请求实例为例,url为 http://localhost:8080/login,body内容为 {"username":"root","password":"123456"}

由于传递的参数是JSON格式,所以Controller中的业务方法的POJO参数必须添加注解 @RequestBody,才能正常接收数据。

1
2
3
4
5
6
7
8
9
@PostMapping("login")
@ResponseBody
public User postLogin(@RequestBody User user) {
System.out.println("post");
System.out.println(user.toString());
user.setUsername(user.getUsername()+"--post");
user.setPassword(user.getPassword()+"--post");
return user;
}

如果User类中不仅忧username和password属性,也可以用来接收body中的username和password参数

总结

前后端数据通信的时候先确定请求的方式。如果是Url类请求,直接将参数拼接到url的query字段是很方便的;如果是Body类请求,则还要确认需要传输的内容:

如果只是普通的数据,比如可以明文的数据,那么没有必要将其封装到body中进行传输,直接将其以 key1=value1&key2=value2 的格式提交给后台是很方便的;

如果是表单数据,当表单内容较多时如果还是将其拼接到url后面,整个url将不是一般的长,又或者是不想让它明文显示在url中的数据,那么将其封装到body中是一个不错的选择。

如果使用基本类型去接收JSON字符串,将不能正常完成请求。

所以进来使用POJO类型。

我总结出两种常用的方式:

  • Url类请求:

    请求参数以 key1=value1&key2=value2 的格式拼接到url后面,提交给后台。后台可以通过@RequestParam或者基本类型和POJO类来进行基本类型参数的接收。(基本类型和POJO类进行接收需要确认属性名和请求参数名称相同)

  • Body类请求:

    请求参数以JSON格式封装到body中提交给后台。后台通过@RequestBody接收数据。

@RequstBody与@RequestParam的区别

  • spring的@RequestParam注解接收的参数是来自于requestHeader中,即请求头。都是用来获取请求路径(url )中的动态参数。也就是在url中,格式为 xxx?username=123&password=456 。功能与@pathvarible类似。
  • RequestBody注解接收的参数则是来自于requestBody中,即请求体中。

@RequestBody的加与不加的区别

  • 使用@requestBody。当请求contentType为:application/json类型的请求,数据类型为json时, json格式如下: {"username":"root","password":"123456"}
  • 不使用@RequestBody.当请求contentType为:application/x-www-form-urlencoded类型的或multipart/form-data时,数据格式为 username=root&password=123456

JQuery的$.ajax(url,[settings])

  1. 默认的ContentType的值为: application/x-www-form-urlencoded; charset=UTF-8此格式为表单提交格式,数据为 key1=value1&key2=value2 的格式 。
  2. 虽然ajax的data属性值格式为: {key1:value1,key2:value2} ,但最后会转为 key1=value1&key2=value2 的格式提交到后台 。
  3. 如果ajax要和SpringMVC交互,要使用 key1=value1&key2=value2 的格式,后台SpringMVC只需要定义对象或者参数就行了,会自动映射(不进行配置的话,自动映射的前提是请求参数的名称和属性名称相同)。
    4.如果SpringMVC的参数有@RequestBody注解(接收json字符串格式数据),ajax必须将date属性值转为json字符串,不能为json对象(js对象,会自动转为key=value形式)。并且,修改contentType的值为: application/json; charset=UTF-8 ,这样加了@RequestBody注解的属性才能自定映射到值。
    5.使用在进行图片或者文件上传时使用 multipart/form-data 类型时、 数据会自动进行映射不要添加任何注解。

找机会开个坑把从后往前写了。

参考资料: