后端开发入门

一、HTTP 协议学习

1. 常用的请求方法

  • GET:用于请求获取指定资源的表示。客户端通过向服务器发送GET请求,服务器会返回请求的资源。这个请求方法通常用于获取数据,比如获取网页内容、图片、视频等。
  • POST:用于向服务器提交数据,这些数据通常用于创建新的资源。通过POST请求,客户端将数据发送给服务器,服务器处理并存储这些数据。POST常用于提交表单数据,例如用户注册或提交评论。
  • PUT:用于向服务器上传数据,从而更新指定的资源。客户端通过PUT请求,将数据发送到服务器上的指定资源位置,从而对该资源进行更新。
  • DELETE:用于请求服务器删除指定的资源。客户端通过DELETE请求,告诉服务器删除指定的资源。
  • PATCH:用于对资源进行局部更新。与PUT请求不同,PATCH请求仅更新资源的部分内容,而不是整个资源。
  • HEAD:类似于GET方法,但服务器只返回响应头部信息,不返回实际的资源内容。这个方法常用于检查资源的元数据,例如验证资源是否存在或最后修改时间。
  • OPTIONS:用于获取目标资源所支持的通信选项。客户端可以通过发送OPTIONS请求来了解服务器支持哪些HTTP方法、允许的头部信息等。
  • TRACE:用于将客户端发出的请求返回回来,用于测试和诊断。服务器会将收到的请求转发回给客户端,以便客户端查看服务器收到的原始请求信息。

2. 请求头

HTTP协议的请求头是在HTTP请求中包含的一组信息,用于向服务器传递附加的数据和元数据。请求头通常是由客户端(例如Web浏览器或应用程序)添加到HTTP请求中,以提供有关请求的更多信息。

  • Host:
    指定目标服务器的主机名和端口号,用于告诉服务器请求的目标地址。例如:Host: www.example.com
协商
  • Accept:
    指定客户端接受的响应数据类型(MIME类型)。客户端可以通过这个头部告诉服务器它能够处理哪些数据类型。例如:Accept: text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8

  • Accept-Language:
    指定客户端接受的自然语言类型,用于告诉服务器客户端希望接收什么语言的响应。例如:Accept-Language: en-US, en;q=0.9, zh-CN;q=0.8

  • Accept-Encoding:
    指定客户端接受的内容编码类型,用于告诉服务器客户端能够解码的内容压缩格式。例如:Accept-Encoding: gzip, deflate

  • Authorization:
    用于在需要进行身份验证的请求中,包含用户凭证的信息。例如:Authorization: Basic base64encoded(username:password)

指定请求体
  • Content-Type:
    指定请求体的数据类型(MIME类型),用于告诉服务器请求体中的数据是什么类型。例如:Content-Type: application/json

  • Content-Length:
    指定请求体的大小,用于告诉服务器请求体中的数据有多大(字节数)。例如:Content-Length: 1024

  • Referer:
    指定当前请求的来源页面,即前一个页面的URL。通常用于告诉服务器请求是从哪个页面链接过来的。例如:Referer: https://www.example.com/previous-page

  • Cookie:
    包含之前由服务器设置的Cookie信息,用于保持状态和身份验证。例如:Cookie: sessionid=abcdef1234567890

3. 响应头

HTTP协议的响应头是服务器在响应客户端的HTTP请求时,包含在响应消息头部的一组信息。这些响应头提供了有关响应的各种信息,例如响应状态码、内容类型、服务器信息等。以下是一些常见的HTTP响应头:

  • Content-Type:
    指定响应体的数据类型(MIME类型),告诉客户端服务器返回的内容是什么类型。例如:Content-Type: text/html; charset=utf-8

  • Content-Length:
    指定响应体的大小,告诉客户端响应体的数据有多大(字节数)。例如:Content-Length: 1024

  • Date:
    指定响应的日期和时间,告诉客户端响应生成的时间。例如:Date: Sun, 25 Jul 2023 12:34:56 GMT

  • Server:
    指定服务器的信息,告诉客户端响应是由哪个服务器生成的。例如:Server: Apache/2.4.41 (Unix)

  • Set-Cookie:
    用于在响应中设置Cookie信息,用于保持状态和身份验证。例如:Set-Cookie: sessionid=abcdef1234567890; Path=/; HttpOnly

  • Cache-Control:
    指定请求和响应的缓存行为。

  • Location:
    用于重定向响应,告诉客户端资源的新位置。

  • Content-Encoding:
    指定响应体的内容编码类型,告诉客户端服务器对响应体进行了何种压缩。

4. 响应状态码

  • 2XX Success(成功状态码)
    200 表示从客户端发来的请求在服务器端被正常处理
    204 该状态码表示服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分
    206 该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求
  • 3XX Redirection(重定向状态码)
    301 永久性重定向
    302 临时性重定向
  • 4XX Client Error(客户端错误状态码)
    400 该状态码表示请求报文中存在语法错误
    401 该状态码表示发送的请求需要有通过HTTP认证的认证信息
    403 该状态码表明对请求资源的访问被服务器拒绝了。
    404 该状态码表明服务器上无法找到请求的资源
    405错误表示"Method Not Allowed",即方法不被允许,意思是对于请求所标识的资源,不允许使用请求行中所指定的方法。
  • 5XX Server Error(服务器错误状态码)
    500 该状态码表明服务器端在执行请求时发生了错误。
    503 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

5. Cookie & Session 的关系

  • Cookie:
    Cookie是在客户端(通常是浏览器)存储少量数据的一种机制。
    服务器通过在HTTP响应头中添加Set-Cookie头部,将Cookie信息发送给客户端。
    客户端会将Cookie保存在本地,每次向同一服务器发起请求时,都会自动将相关的Cookie信息包含在HTTP请求头中,发送给服务器。
    Cookie通常用于跟踪用户的状态和存储用户偏好设置。例如,登录状态、语言偏好、购物车内容等都可以通过Cookie保存在客户端。
  • Session:
    Session是服务器端的一种机制,用于跟踪用户在同一网站的活动状态。
    当用户第一次访问服务器时,服务器会为该用户创建一个唯一的Session标识,并将该标识保存在Cookie中(通常名为sessionid)。
    之后,客户端每次向服务器发起请求时,都会自动带上这个sessionid标识,用于告诉服务器请求来自于哪个用户。
    服务器根据收到的sessionid来查找相应的Session数据,从而判断用户的状态,存储购物车信息、用户认证状态等。
  • 关系:
    Cookie和Session通常一起使用,配合实现用户状态管理和会话跟踪。
    用户第一次访问网站时,服务器为其创建一个Session,并将Session的标识(sessionid)保存在Cookie中,发送给客户端。
    客户端在以后的每次请求中都会自动带上这个Cookie,服务器通过其中的sessionid找到对应的Session数据,从而恢复用户的状态。
    通过Cookie和Session的配合使用,服务器可以有效地跟踪用户的会话信息,保持用户状态的连续性,并提供个性化的服务。例如,用户登录后,在整个会话期间保持登录状态,同时可以根据用户Session中的数据展示相应的个性化内容。

二、从头搭建 Spring Boot 工程

在Spring官网(https://start.spring.io/)自定义选项搭建。

三、练习 Spring MVC 常用注解

常见命令:

POST请求

curl -i -X POST \
  -H 'Content-Type: application/json' \
  -d '{"account": "admin", "password": "xxt123@XXT"}' \
  http://zentao.xxt.cn/zentao/api.php/v1/tokens
GET 请求
curl -i \
  -H 'Content-Type: application/json' \
  http://localhost:8080/failure/test100101?timeoutMills=1

1. 简单练习一

package com.xxt.SpringPractice;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/demo")
public class GetController {
    // 处理GET请求,映射到路径 /demo/hello
    @GetMapping("/hello")
    public String helloGet() {
        return "Hello, GET request";
    }
    /*
    xxt@mawenbo ~ % curl -i http://localhost:8080/demo/hello
    HTTP/1.1 200
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 18
    Date: Tue, 25 Jul 2023 08:21:19 GMT

    Hello, GET request%
     */

    // 处理POST请求,映射到路径 /demo/hello
    @PostMapping("/hello")
    public String helloPost() {
        return "Hello, POST request";
    }
    /*
    xxt@mawenbo ~ % curl -i -X POST http://localhost:8080/demo/hello
    HTTP/1.1 200 
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 19
    Date: Tue, 25 Jul 2023 08:23:40 GMT
    
    Hello, POST request%     
     */
}

2.GetController

package com.xxt.SpringPractice;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.awt.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping(value = "/test02", produces = MediaType.APPLICATION_JSON_VALUE)
@Slf4j


public class GetController01 {
    @PostMapping("test0201")
    public String test0101(@RequestBody Student student) {
        log.info("test0201 called. student: {}", student);
        return student != null ? student.toString() : null;
    }
    /*
    xxt@mawenbo ~ % curl -i -X POST -H "Content-Type: application/json" -d '{"name": "mwb", "age": 3}' http://localhost:8080/test02/test0201


    HTTP/1.1 200
    Content-Type: application/json
    Content-Length: 24
    Date: Tue, 25 Jul 2023 09:20:09 GMT

    Student(name=mwb, age=3)%
     */

    @GetMapping("test0202")
    public String test0202() {
        log.info("test0202 called and return chinese word");
        return "中文";
    }
    //curl -i -X GET -H "Accept-Charset: UTF-8" http://localhost:8080/test0202
    /*
    xxt@mawenbo ~ % curl -i -X GET -H "Accept-Charset: UTF-8" http://localhost:8080/test02/test0202
    HTTP/1.1 200
    Content-Type: application/json
    Content-Length: 6
    Date: Tue, 25 Jul 2023 09:28:08 GMT

    中文%
     */


    @GetMapping("test0203")
    public List<Date> test0203() {
        log.info("test0203 called and return date list");
        List<Date> result = new ArrayList<>();
        result.add(new Date());
        result.add(new Date());
        result.add(new Date());
        result.add(null);
        return result;
    }
    /*
    xxt@mawenbo ~ % curl -i -X GET -H "Accept-Charset: UTF-8" http://localhost:8080/test02/test0203
    HTTP/1.1 200
    Content-Type: application/json
    Transfer-Encoding: chunked
    Date: Tue, 25 Jul 2023 09:28:26 GMT

    ["2023-07-25T09:28:26.308+00:00","2023-07-25T09:28:26.308+00:00","2023-07-25T09:28:26.308+00:00",null]%
     */

    @GetMapping("test0204")
    public void test0204(@RequestParam(required = false) String name) {
        log.info("test0204 called with params:name={}", name);
    }
    /*
    xxt@mawenbo ~ % curl -i -X GET -H "Accept-Charset: UTF-8" http://localhost:8080/test02/test0204
    HTTP/1.1 200
    Content-Length: 0
    Date: Tue, 25 Jul 2023 09:28:54 GMT
    控制台:test100101 called with params:name=null
     */
}

3. PostController

package com.xxt.SpringPractice;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping(value = "/test01", produces = MediaType.APPLICATION_JSON_VALUE)
@Slf4j

public class PostController {
    @PostMapping("test0101")
    public String test0101(@RequestBody Student student) {
        log.info("test01 called. student: {}", student);
        return student != null ? student.toString() : null;
    }
    // 传入一个对象
    /*
    xxt@mawenbo ~ % curl -i -X POST -H "Content-Type: application/json" -d '{"name":"wenbo", "age": 20}' http://localhost:8080/test01/test0101
    HTTP/1.1 200
    Content-Type: application/json
    Content-Length: 27
    Date: Tue, 25 Jul 2023 08:53:41 GMT

    Student(name=wenbo, age=20)%
     */

    @PostMapping("test0102")
    public String test0102(@RequestBody List<Student> students) {
        log.info("test0102 called. students: {}", students);
        return students != null ? students.toString() : null;
    }
    // 一次传入多个对象
    /*
    xxt@mawenbo ~ % curl -i -X POST -H "Content-Type: application/json" -d '[{"name":"mawenbo", "age": 20}, {"name":"maxiaobo", "age": 18}, {"name":"mayibo", "age": 19}]' http://localhost:8080/test01/test0102
    HTTP/1.1 200
    Content-Type: application/json
    Content-Length: 93
    Date: Tue, 25 Jul 2023 09:08:54 GMT

    [Student(name=mawenbo, age=20), Student(name=maxiaobo, age=18), Student(name=mayibo, age=19)]%
     */

}

@Data
class Student {
    private String name;
    private int age;
}