Reprinted: Web request and response (SpringBoot)

Web request and response

How the Web works can be broken down into the following steps:

  1. Input URL: The web client uses a web browser to input the URL (uniform resource locator) to be accessed.

  2. Establish a connection: A TCP/IP connection is established between the web browser and the web server for data transmission.

  3. Send HTTP request: The web browser sends an HTTP request to the web server, requesting the required web resources.

  4. Receive HTTP response: The web server receives the HTTP request and sends the web resource to the web browser via the HTTP response.

  5. Rendering the Web page: The Web browser receives the HTTP response and renders the Web page based on the received data for presentation to the user.

  6. Close Connection: The TCP/IP connection between the web browser and the web server is closed.

What is an HTTP request?

HTTP (Hypertext Transfer Protocol) is a protocol used for communication between a web server and a client (browser) to transfer data over the Internet. An HTTP request is a message sent by a client to a server requesting a specific resource, such as a web page, image, or video. The HTTP request method determines the type of request, such as GET, POST, PUT, DELETE, HEAD, OPTIONS, CONNECT, TRACE, etc.

The structure of an HTTP request:

An HTTP request consists of a request line, headers, and an optional message body.

The request line includes the HTTP method, the URL (Uniform Resource Locator) of the requested resource, and the HTTP version being used.

Headers provide additional information about the request, such as the user agent, requested content type, and acceptable encoding formats.

The message body is optional and contains data such as form data or JSON.

HTTP request method:

HTTP defines various request methods that indicate the operation to be performed on the resource identified by the URL. The most common HTTP request methods are:

  1. GET: Get a resource, such as a web page or an image, from the server.

  2. POST: Submits data to the server for processing, such as form submission or file upload.

  3. PUT: Updates an existing resource on the server with new data.

  4. DELETE: Delete a resource from the server.

  5. HEAD: Retrieves the header of the resource, without the message body.

  6. OPTIONS: Used to obtain the methods supported by the current URL. If the request is successful, it will include a header named "Allow" in the HTTP header, and the value is the supported method, such as "GET, POST".

  7. CONNECT: Establishes a network connection to a resource, such as a proxy server.

  8. TRACE: Echoes received request messages for debugging purposes. HTTP headers:

HTTP headers are used to provide additional information about an HTTP request or response. They are colon-separated key-value pairs included in a request or response message. There are many types of headers, such as general headers, request headers, response headers, and entity headers. Some common headers include:

  1. User-Agent: Provide the identification of the browser type, operating system and version, CPU type, browser rendering engine, browser language, browser plug-in and other information you are using to the visiting website

  2. Accept: Specifies the content types accepted by the client.

  3. Content-Type: Specifies the type of content in the request or response message.

  4. Content-Length: Specifies the length of the message body in bytes.

  5. Cache-Control: Specifies caching directives for responses, such as max-age and must-revalidate.

  6. Authorization: Specifies the authentication credentials for the request. HTTP message body:

The HTTP message body is an optional part of an HTTP request or response and contains data in various formats, such as HTML, JSON, XML, or binary data. In a request, the message body contains data to be sent to the server, such as form data or a file upload. In a response, the message body contains the actual content of the requested resource, such as an HTML page or image.

In summary, understanding the basics of http requests and responses is critical to web development and communication between web servers and clients. By understanding how HTTP requests are constructed, the various request methods, use of headers, and optional message bodies, developers can effectively communicate with servers and create robust web applications.

What is an HTTP response?

An HTTP response is a response to a request sent by the server to the client. An HTTP response contains the following components:

  1. HTTP version

  2. status code

  3. status message

  4. response header

  5. response body

1. HTTP version

The HTTP version used in the response is specified in the first line of the response. For example:

HTTP/1.1 200 OK

This specifies that the response is sent using HTTP version 1.1.

2. Status code

The status code indicates the result of the requested operation. HTTP defines five types of status codes:

  1. Information prompt (100-199)

  2. Success (200-299)

  3. Redirect (300-399)

  4. Client errors (400-499)

  5. Server errors (500-599) Each status code is a three-digit number included in the first line of the response after the HTTP version. For example:

HTTP/1.1 200 OK

This indicates that the operation was successful and the requested resource is included in the response body.

3. Status information

A status message is a description of the status code. It is included in the first line of the response after the status code. For example:

HTTP/1.1 404 Not Found

This indicates that the requested resource was not found, and the status message provides a short description of the problem.

4. Response header

Response headers contain metadata about the response. They are similar to request headers, but provide information about the response rather than the request. Response headers can include information about the server, caching policy, cookies, and more.

Response headers are included in the response after the first line. Each header is a key-value pair separated by colons. For example:

HTTP/1.1 200 OK

Content-Type: text/html

Content-Length: 1274

Server: Apache

In this example, the response contains three headers: Content-Type, Content-Length, and Server.

5. Response body

The response body contains the requested resource or an error message if the requested resource could not be found. The format of the response body depends on the Content-Type header included in the response. For example, if the Content-Type header is set to "text/html", the response body should contain HTML code.

The response body is included in the response after the response headers. If the response body is large, it may be split into multiple packets.

Technical points of HTTP request and response

HTTP requests and responses have several technical points that developers need to be aware of. These technical points determine how requests and responses are constructed and transmitted between the client and server.

1. Request and response headers

HTTP requests and responses contain headers that provide additional information about the request or response. Headers are key-value pairs sent in message headers that convey metadata about the request or response. There are several types of headers, including generic headers, request headers, response headers, and entity headers.

Generic headers apply to both requests and responses and provide information about the entire message, such as the message format, date and time it was sent, and whether the message can be cached.

Request headers are used to provide information about the client making the request, such as the user agent (the software used to access the server), the types of content accepted, and the encoding used to compress the message body.

The response header provides information about the server's response to the client's request, such as the content type of the response, the length of the message body, whether the response can be cached, and so on.

Entity headers are used to provide information about the message body, such as content-length and content-encoding.

2. HTTP method

An HTTP request uses a set of methods to specify the desired action to be performed on the resource identified in the URL. The most common HTTP methods are GET, POST, PUT, DELETE, and HEAD.

  1. GET: Used to retrieve data from the server.

  2. POST: Used to send data to the server to create or update a resource.

  3. PUT: Used to update an existing resource on the server.

  4. DELETE: Used to delete resources from the server.

  5. HEAD: Used to retrieve the headers of the resource, not the message body. HTTP Status Codes HTTP responses include status codes that indicate the status of the request. There are five categories of status codes, each with its own set of codes:

• 1xx: Informational - Indicates that the server has received the request and is continuing to process it. • 2xx: Success - Indicates that the request was successfully received, understood and accepted. • 3xx: Redirect - Indicates that the client needs to take further action to complete the request. • 4xx: Client Error - Indicates that the request contained bad syntax or could not be fulfilled. • 5xx: Server Error - Indicates that the server failed to fulfill a valid request. The most common status codes are 200 OK (the request was successful), 404 Not Found (the requested resource was not found), and 500 Internal Server Error (the server encountered an error while processing the request).

3、Cookies

HTTP requests and responses can also include cookies, which are small text files that are stored on the client computer. Cookies are used to store information about client preferences or previous interactions with the server. Servers can use cookies to identify clients and serve customized content.

4. Cache

HTTP requests and responses can also be cached, meaning that a client or intermediary server can store a copy of the response for future use. Caching can help reduce network traffic and improve performance, but can also cause problems if the cached content is outdated or stale.

1. Based on SpringBoot request

Request (HttpServletRequest): Get request data

Enter the address in the browser address, click Enter to request the server, this process is a request process.

1.1 Simple parameters

1.1.1 Original way

In the original Web program, it is necessary to obtain the relevant information of the request through the API provided in the Servlet: HttpServletRequest (request object). For example, to get request parameters:

When Tomcat receives the Http request: encapsulate the relevant information of the request into the HttpServletRequest object.

In the Controller, if we want to get the Request object, we can directly declare the HttpServletRequest object in the formal parameter of the method. Then you can get the request information through this object:

 
 
//根据指定的参数名获取请求参数的数据值
String  request.getParameter("参数名")
 
 
@RestController
public class RequestController {
   //原始方式
   @RequestMapping("/simpleParam")
   public String simpleParam(HttpServletRequest request){
       // http://localhost:8080/simpleParam?name=Tom&age=10
       // 请求参数: name=Tom&age=10   (有2个请求参数)
       // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
       // 第2个请求参数: age=10     参数名:age , 参数值:10
       String name = request.getParameter("name");//name就是请求参数名
       String ageStr = request.getParameter("age");//age就是请求参数名
       int age = Integer.parseInt(ageStr);//需要手动进行类型转换
       System.out.println(name+" : "+age);
       return "OK";
  }
}

1.1.2 Spring Boot method

In the Springboot environment, the original API is encapsulated, and the form of receiving parameters is simpler. If it is a simple parameter, the parameter name is the same as the variable name of the formal parameter, and the parameter can be received by defining a formal parameter with the same name.

 
 
@RestController
public class RequestController {
   // http://localhost:8080/simpleParam?name=Tom&age=10
   // 第1个请求参数: name=Tom   参数名:name,参数值:Tom
   // 第2个请求参数: age=10     参数名:age , 参数值:10
   
   //springboot方式
   @RequestMapping("/simpleParam")
   public String simpleParam(String name , Integer age ){//形参名和请求参数名保持一致
       System.out.println(name+" : "+age);
       return "OK";
  }
}

Conclusion: Whether it is a GET request or a POST request, for simple parameters, as long as the == request parameter name is consistent with the formal parameter name in the Controller method ==, the data value in the request parameter can be obtained.

1.1.3 Parameter names are inconsistent

If the method parameter name is inconsistent with the request parameter name, can the parameter in the controller method still receive the request parameter value?

 
 
@RestController
public class RequestController {
   // http://localhost:8080/simpleParam?name=Tom&age=20
   // 请求参数名:name
   //springboot方式
   @RequestMapping("/simpleParam")
   public String simpleParam(String username , Integer age ){//请求参数名和形参名不相同
       System.out.println(username+" : "+age);
       return "OK";
  }
}

Answer: No errors were reported during operation. The username value in the controller method is: null, and the age value is 20

  • Conclusion: For simple parameters, if the request parameter name is inconsistent with the formal parameter name in the controller method, the request data cannot be received

那么如果我们开发中,遇到了这种请求参数名和controller方法中的形参名不相同,怎么办?

解决方案:可以使用Spring提供的@RequestParam注解完成映射

在方法形参前面加上 @RequestParam 然后通过value属性执行请求参数名,从而完成映射。代码如下:

 
 
@RestController
public class RequestController {
   // http://localhost:8080/simpleParam?name=Tom&age=20
   // 请求参数名:name
   //springboot方式
   @RequestMapping("/simpleParam")
   public String simpleParam(@RequestParam("name") String username , Integer age ){
       System.out.println(username+" : "+age);
       return "OK";
  }
}

注意事项:

@RequestParam中的required属性默认为true(默认值也是true),代表该请求参数必须传递,如果不传递将报错

如果该参数是可选的,可以将required属性设置为false

 
  
@RequestMapping("/simpleParam")
public String simpleParam(@RequestParam(name = "name", required = false) String username, Integer age){
System.out.println(username+ ":" + age);
return "OK";
}

1.2实体参数

在使用简单参数做为数据传递方式时,前端传递了多少个请求参数,后端controller方法中的形参就要书写多少个。如果请求参数比较多,通过上述的方式一个参数一个参数的接收,会比较繁琐。

此时,我们可以考虑将请求参数封装到一个实体类对象中。 要想完成数据封装,需要遵守如下规则:请求参数名与实体类的属性名相同

1.2.1简单实体类对象

定义POJO实体类:

 
 
public class User {
   private String name;
   private Integer age;
   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }
   public Integer getAge() {
       return age;
  }
   public void setAge(Integer age) {
       this.age = age;
  }
   @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", age=" + age +
               '}';
  }
}

Controller方法

 
 
@RestController
public class RequestController {
   //实体参数:简单实体对象
   @RequestMapping("/simplePojo")
   public String simplePojo(User user){
       System.out.println(user);
       return "OK";
  }
}

1.2.2复杂实体类对象

上面我们讲的呢是简单的实体对象,下面我们在来学习下复杂的实体对象。

复杂实体对象指的是,在实体类中有一个或多个属性,也是实体对象类型的。如下:

  • User类中有一个Address类型的属性(Address是一个实体类)

复杂实体对象的封装,需要遵守如下规则:

  • 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套实体类属性参数。

定义POJO实体类:

  • Address实体类

 
 
public class Address {
   private String province;
   private String city;
   public String getProvince() {
       return province;
  }
   public void setProvince(String province) {
       this.province = province;
  }
   public String getCity() {
       return city;
  }
   public void setCity(String city) {
       this.city = city;
  }
   @Override
   public String toString() {
       return "Address{" +
               "province='" + province + '\'' +
               ", city='" + city + '\'' +
               '}';
  }
}
  • User实体类

 
 
public class User {
   private String name;
   private Integer age;
   private Address address; //地址对象
   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }
   public Integer getAge() {
       return age;
  }
   public void setAge(Integer age) {
       this.age = age;
  }
   public Address getAddress() {
       return address;
  }
   public void setAddress(Address address) {
       this.address = address;
  }
   @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", address=" + address +
               '}';
  }
}

Controller方法:

 
 
@RestController
public class RequestController {
   //实体参数:复杂实体对象
   @RequestMapping("/complexPojo")
   public String complexPojo(User user){
       System.out.println(user);
       return "OK";
  }
}

Postman测试:

1.3数组集合参数

数组集合参数的使用场景:在HTML的表单中,有一个表单项是支持多选的(复选框),可以提交选择的多个值。

后端程序接收上述多个值的方式有两种:

  1. 数组

  2. 集合

1.3.1数组

数组参数:请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数

Controller方法:

 
 
@RestController
public class RequestController {
   //数组集合参数
   @RequestMapping("/arrayParam")
   public String arrayParam(String[] hobby){
       System.out.println(Arrays.toString(hobby));
       return "OK";
  }
}

Postman测试:

在前端请求时,有两种传递形式:

方式一:http://localhost:8080/arrayParam?hobby=game&hobby=java

方式二:http://localhost:8080/arrayParam?hobby=game,java

1.3.2集合

集合参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系

默认情况下,请求中参数名相同的多个值,是封装到数组。如果要封装到集合,要使用@RequestParam绑定参数关系

Controller方法:

 
 
@RestController
public class RequestController {
   //数组集合参数
   @RequestMapping("/listParam")
   public String listParam(@RequestParam List<String> hobby){
       System.out.println(hobby);
       return "OK";
  }
}

Postman测试:

方式一:http://localhost:8080/listParam?hobby=game&hobby=java

方式二:http://localhost:8080/listParam?hobby=game,java

1.4日期函数

上述演示的都是一些普通的参数,在一些特殊的需求中,可能会涉及到日期类型数据的封装。比如,如下需求:

因为日期的格式多种多样(如:2022-12-12 10:05:45 、2022/12/12 10:05:45),那么对于日期类型的参数在进行封装的时候,需要通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。

  • @DateTimeFormat注解的pattern属性中指定了哪种日期格式,前端的日期参数就必须按照指定的格式传递。

  • 后端controller方法中,需要使用Date类型或LocalDateTime类型,来封装传递的参数。

Controller方法:

 
 
@RestController
public class RequestController {
   //日期时间参数
  @RequestMapping("/dateParam")
   public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
       System.out.println(updateTime);
       return "OK";
  }
}

1.5JSON参数

如果是比较复杂的参数,前后端通过会使用JSON格式的数据进行传输。 (JSON是开发中最常用的前后端数据交互方式)

我们学习JSON格式参数,主要从以下两个方面着手:

  1. Postman在发送请求时,如何传递json格式的请求参数

  2. 在服务端的controller方法中,如何接收json格式的请求参数

Postman发送JSON格式数据:

服务端Controller方法接收JSON格式数据:

  • 传递json格式的参数,在Controller中会使用实体类进行封装。

  • 封装规则:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数。需要使用 @RequestBody标识。

  • @RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)

实体类:Address

 
 
public class Address {
   private String province;
   private String city;
   
//省略GET , SET 方法
}

实体类:User

 
 
public class User {
   private String name;
   private Integer age;
   private Address address;
   
   //省略GET , SET 方法
}    

Controller方法:

 
 
@RestController
public class RequestController {
   //JSON参数
   @RequestMapping("/jsonParam")
   public String jsonParam(@RequestBody User user){
       System.out.println(user);
       return "OK";
  }
}

Postman测试:

1.6路径参数

传统的开发中请求参数是放在请求体(POST请求)传递或跟在URL后面通过?key=value的形式传递(GET请求)。

在现在的开发中,经常还会直接在请求的URL中传递参数。例如:

 
 
http://localhost:8080/user/1
http://localhost:880/user/1/0

上述的这种传递请求参数的形式呢,我们称之为:路径参数。

学习路径参数呢,主要掌握在后端的controller方法中,如何接收路径参数。

路径参数:

  • 前端:通过请求URL直接传递参数

  • 后端:使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数

Controller方法:

 
 
@RestController
public class RequestController {
   //路径参数
   @RequestMapping("/path/{id}")
   public String pathParam(@PathVariable Integer id){
       System.out.println(id);
       return "OK";
  }
}

传递多个路径参数:

Controller方法:

 
 
@RestController
public class RequestController {
   //路径参数
   @RequestMapping("/path/{id}/{name}")
   public String pathParam2(@PathVariable Integer id, @PathVariable String name){
       System.out.println(id+ " : " +name);
       return "OK";
  }
}

2.基于SpringBoot响应

响应(HttpServletReponse):设置响应数据

服务器根据浏览器发送的请求,放回数据到浏览器在网页上进行显示的过程就叫响应。

2.1@ResponseBody

controller方法中的return的结果,怎么就可以响应给浏览器呢?

答案:使用@ResponseBody注解

@ResponseBody注解:

  • 类型:方法注解、类注解

  • 位置:书写在Controller方法上或类上

  • 作用:将方法返回值直接响应给浏览器

    • 如果返回值类型是实体对象/集合,将会转换为JSON格式后在响应给浏览器

但是在我们所书写的Controller中,只在类上添加了@RestController注解、方法添加了@RequestMapping注解,并没有使用@ResponseBody注解,怎么给浏览器响应呢?

 
 
@RestController
public class HelloController {
   @RequestMapping("/hello")
   public String hello(){
       System.out.println("Hello World ~");
       return "Hello World ~";
  }
}

原因:在类上添加的@RestController注解,是一个组合注解。

  • @RestController = @Controller + @ResponseBody

@RestController源码:

 
 
@Target({ElementType.TYPE})   //元注解(修饰注解的注解)
@Retention(RetentionPolicy.RUNTIME)  //元注解
@Documented    //元注解
@Controller  
@ResponseBody
public @interface RestController {
   @AliasFor(
       annotation = Controller.class
  )
   String value() default "";
}

结论:在类上添加@RestController就相当于添加了@ResponseBody注解。

  • 类上有@RestController注解或@ResponseBody注解时:表示当前类下所有的方法返回值做为响应数据

    • 方法的返回值,如果是一个POJO对象或集合时,会先转换为JSON格式,在响应给浏览器

下面我们来测试下响应数据:

 
 
@RestController
public class ResponseController {
   //响应字符串
   @RequestMapping("/hello")
   public String hello(){
       System.out.println("Hello World ~");
       return "Hello World ~";
  }
   //响应实体对象
   @RequestMapping("/getAddr")
   public Address getAddr(){
       Address addr = new Address();//创建实体类对象
       addr.setProvince("广东");
       addr.setCity("深圳");
       return addr;
  }
   //响应集合数据
   @RequestMapping("/listAddr")
   public List<Address> listAddr(){
       List<Address> list = new ArrayList<>();//集合对象
       
       Address addr = new Address();
       addr.setProvince("广东");
       addr.setCity("深圳");
       Address addr2 = new Address();
       addr2.setProvince("陕西");
       addr2.setCity("西安");
       list.add(addr);
       list.add(addr2);
       return list;
  }
}

在服务端响应了一个对象或者集合,那私前端获取到的数据是什么样子的呢?我们使用postman发送请求来测试下。测试效果如下:

2.2统一响应结果

大家有没有发现一个问题,我们在前面所编写的这些Controller方法中,返回值各种各样,没有任何的规范。

如果我们开发一个大型项目,项目中controller方法将成千上万,使用上述方式将造成整个项目难以维护。那在真实的项目开发中是什么样子的呢?

在真实的项目开发中,无论是哪种方法,我们都会定义一个统一的返回结果。方案如下:

前端:只需要按照统一格式的返回结果进行解析(仅一种解析方案),就可以拿到数据。

统一的返回结果使用类来描述,在这个结果中包含:

  • 响应状态码:当前请求是成功,还是失败

  • 状态码信息:给页面的提示信息

  • 返回的数据:给前端响应的数据(字符串、对象、集合)

定义在一个实体类Result来包含以上信息。代码如下:

 
 
public class Result {
   private Integer code;//响应码,1 代表成功; 0 代表失败
   private String msg;  //响应码 描述字符串
   private Object data; //返回的数据
public Result() { }
public Result(Integer code, String msg, Object data) {
   this.code = code;
   this.msg = msg;
   this.data = data;
}
public Integer getCode() {
   return code;
}
public void setCode(Integer code) {
   this.code = code;
}
public String getMsg() {
   return msg;
}
public void setMsg(String msg) {
   this.msg = msg;
}
public Object getData() {
   return data;
}
public void setData(Object data) {
   this.data = data;
}
//增删改 成功响应(不需要给前端返回数据)
public static Result success(){
   return new Result(1,"success",null);
}
//查询 成功响应(把查询结果做为返回数据响应给前端)
public static Result success(Object data){
   return new Result(1,"success",data);
}
//失败响应
public static Result error(String msg){
   return new Result(0,msg,null);
}
}

改造Controller:

 
 
@RestController
public class ResponseController {
   //响应统一格式的结果
   @RequestMapping("/hello")
   public Result hello(){
       System.out.println("Hello World ~");
       //return new Result(1,"success","Hello World ~");
       return Result.success("Hello World ~");
  }
   //响应统一格式的结果
   @RequestMapping("/getAddr")
   public Result getAddr(){
       Address addr = new Address();
       addr.setProvince("广东");
       addr.setCity("深圳");
       return Result.success(addr);
  }
   //响应统一格式的结果
   @RequestMapping("/listAddr")
   public Result listAddr(){
       List<Address> list = new ArrayList<>();
       Address addr = new Address();
       addr.setProvince("广东");
       addr.setCity("深圳");
       Address addr2 = new Address();
       addr2.setProvince("陕西");
       addr2.setCity("西安");
       list.add(addr);
       list.add(addr2);
       return Result.success(list);
  }
}

使用Postman测试:

Guess you like

Origin blog.csdn.net/qq_36256590/article/details/130641091