RESTful接口web服务

  • HTTP协议
  • 简介
  • 工作原理
  • HTTP请求过程
  • HTTP请求方式
  • HTTP报头
  • RESTful接口
  • 项目实例
  • 项目创建
  • 测试
  • 总结

HTTP协议

简介

  HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。。
  HTTP是一个基于TCP/IP通信协议来传递数据HTML 文件, 图片文件, 查询结果等

工作原理

HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过url向HTTP服务端即web服务器发送请求

  1. HTTP协议采用请求/相应模式。客户端发送请求,包含方法、url、协议版本等。
  2. 服务器以一状态行为作为相应,包括协议版本,成功或者失败信息,响应数据等。

web服务器有:Apache IIS

web服务器根据接受请求,向客户端发送相应信息

HTTP默认端口号为80

java springboot初始化udp单播_restful

注意事项:

  1. HTTP是无连接
      每次连接只处理一个请求。服务器处理完客户的请求,收到客户端应答后,断开连接,节省传输时间
  2. HTTP是媒体独立的
      只要客户端和服务器知道如何处理数据内容,任何数据类型都可以通过HTTP发送
  3. HTTP是无状态的
      无状态协议,对事物处理无记忆能力。后续处理需要前面的信息,需要重新进行传输,导致连接传输数据量加大

HTTP请求过程

  1. 通过DNS对域名进行解析:浏览器缓存->操作系统缓存->hosts文件->DNS服务器
  2. 通过TCP协议,建立浏览器与服务器端连接
  3. 浏览器发起HTTP协议请求
  4. 服务器响应HTTP请求
  5. 浏览器解析html代码,并请求Html资源
  6. 浏览器展示内容
  7. TCP断开连接

HTTP请求方式

请求方法

操作方式

GET

GET方法要求服务器将url定位的资源放在响应报文的数据部分,回送给客户端

POST

向服务器提交数据,将数据交由服务器处理

HEAD

获取响应头

PUT

替换资源

DELETE

删除资源

OPTIONS

允许客户端查看服务器性能

TRACE

回应服务器收到的请求,用于测试或诊断

HTTP报头

一. HTTP请求报文
请求报头由四部分构成,请求行、请求头、空行和请求数据

  1. 请求行
  2. java springboot初始化udp单播_http_02

  3. 请求头
  4. java springboot初始化udp单播_客户端_03

  5. User-Agent:产生请求的浏览器类型;
    Accept:客户端可识别的响应内容类型列表;星号 “ * ” 用于按范围将类型分组,用 “ / ” 指示可接受全部类型,用“ type/* ”指示可接受 type 类型的所有子类型;
    Accept-Language:客户端可接受的自然语言;
    Accept-Encoding:客户端可接受的编码压缩格式;
    Accept-Charset:可接受的应答的字符集;
    Host:请求的主机名,允许多个域名同处一个IP 地址,即虚拟主机;
    connection:连接方式(close 或 keepalive);
    Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie;
  6. 空行
  7. java springboot初始化udp单播_http_04

  8. 请求数据
    请求包体不在 GET 方法中使用,而是在POST 方法中使用。POST 方法适用于需要客户填写表单的场合

二. HTTP响应报文

HTTP响应报文由响应行,响应头,响应体三部分组成

java springboot初始化udp单播_HTTP_05


响应行主要包括

响应协议,这个与请求协议对应,比如http,
    状态码1xx
    状态码的描述OK

响应头就是一些常见的响应名对应的响应值
响应参数就是我们真正需要的从数据库中取出的数据

  1. 状态码:三位数字组成:第一位数字表示响应类型
    (1)1xx: 服务器接收客户请求
    (2)2xx: 服务器接收请求并处理
    (3)3xx: 服务器要求客户端重定向
    (4)4xx: 客户端请求有非法内容
    (5)5xx: 服务器未能正常处理出错

状态码实例
(1) 200 OK:表示客户端请求成功;
(2) 400 Bad Request:表示客户端请求有语法错误,不能被服务器所理解;
(3) 404 Not Found:请求的资源不存在,例如,输入了错误的URL;
(4) 500 Internal Server Error:表示服务器发生不可预期的错误,导致无法完成客户端的请求;
(5) 503 Service Unavailable:表示服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常;

  1. 响应头
    响应头包括Location,Server,Vary,Connection等
    Location:Location响应报头域用于重定向接受者到一个新的位置
    Server:Server 响应报头域包含了服务器用来处理请求的软件信息及其版本
    Vary:指示不可缓存的请求头列表
    Connection:连接方式;
  2. 空行
  3. 响应体
    服务器返回给客户端的文本信息

RESTful接口

API:一组编程接口规范,客户端与服务端通过请求响应进行数据通信
REST:表述性传递,决定了接口的形式与规则。RESTful是基于http方法的API设计风格

  1. 通过Url可以知道获取需要什么资源
  2. 通过http method获取针对资源做什么
  3. http status code知道结果

当然也不是所有的接口,都能用REST的形式来表述。在实际工作中,灵活运用,我们用RESTful风格的目的是为大家提供统一标准,避免不必要的沟通成本的浪费,形成一种通用的风格。

  1. RESTful是面向资源的

符合REST接口URI

功能

GET /api/cats/{id}

获取一个小猫

GET /api/cats

获取所有小猫

POST /api/cats

添加一个小猫

PUT /api/cats/{id}

修改一个小猫

DELETE /api/cats/{id}

删除一个小猫

  1. HTTP方法对资源进行操作
    GET : 获取、读取资源
    POST : 添加资源
    PUT : 修改资源
    DELETE : 删除资源
  2. HTTP状态码
      所有事情都按预期正确执行完毕 - 成功
      APP 发生了一些错误 – 客户端错误
      API 发生了一些错误 – 服务器端错误
  3. Get方法和查询参数不应改变
    修改数据是post,put,delete
  4. 是用复数名词
  5. 复杂关系固定表达
    GET /cars/711/drivers/ 返回 使用过编号711汽车的所有司机
  6. 高级用法:HATEOAS
    返回结果中提供链接,连接其他API方法,用户不查询文档,也能熟知下一步操作
    可以通过link属性得知下一步用什么Api
{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}
  1. 资源过滤,排序,选择和分页表述
  2. 版本化Api

项目实例

项目创建

java springboot初始化udp单播_客户端_06


java springboot初始化udp单播_restful_07


默认操作next,可自行修改Group,Artifact

java springboot初始化udp单播_HTTP_08


java springboot初始化udp单播_HTTP_09

BaseRequestController

package com.jady.retrofitclientserver.controller;

import com.jady.retrofitclientserver.model.DeleteBody;
import com.jady.retrofitclientserver.model.ServerResult;
import com.jady.retrofitclientserver.model.User;
import com.jady.retrofitclientserver.model.UserForLogin;
import org.springframework.web.bind.annotation.*;

/**
 * Created by lipingfa on 2017/6/16.
 */
@RestController
public class BaseRequestController {
    /**
     * get请求
     *
     * @return
     */
    @GetMapping("/user/info")
    public ServerResult getUser() {
        ServerResult serverResult = new ServerResult<User>();
        serverResult.setServer_time(System.currentTimeMillis());
        serverResult.setSuccess(true);
        User user = new User("jady", 12);
        serverResult.setData(user);
        return serverResult;
    }

    @PostMapping("/user/login")
    public ServerResult login(@RequestParam String name, @RequestParam String password) {
        ServerResult serverResult = new ServerResult<String>();
        serverResult.setServer_time(System.currentTimeMillis());
        if ("jady".equals(name) && "1234".equals(password)) {
            serverResult.setSuccess(true);
            serverResult.setData("addafeas_cdedhyuj_daledage_leiaefss");
        } else {
            serverResult.setSuccess(false);
            serverResult.setErr_code("1000");
            serverResult.setMessage("用户名或密码错误");
        }
        return serverResult;
    }

    @PostMapping(path = "/user/loginByBody")
    public ServerResult login(@RequestBody UserForLogin userForLogin) {
        ServerResult serverResult = new ServerResult<String>();
        serverResult.setServer_time(System.currentTimeMillis());
        if ("jady".equals(userForLogin.getName()) && "1234".equals(userForLogin.getPassword())) {
            serverResult.setSuccess(true);
            serverResult.setData("addafeas_cdedhyuj_daledage_leiaefss");
        } else {
            serverResult.setSuccess(false);
            serverResult.setErr_code("1000");
            serverResult.setMessage("用户名或密码错误");
        }
        return serverResult;
    }

    @PutMapping(path = "/user/update")
    public ServerResult updateUserInfo(@RequestHeader("access_token") String accessToken, @RequestParam(required = false) String name, @RequestParam(required = false) String age) {
        ServerResult serverResult = new ServerResult();
        serverResult.setServer_time(System.currentTimeMillis());
        if ("1234".equals(accessToken)) {
            //更新用户信息
            serverResult.setSuccess(true);
        } else {
            serverResult.setSuccess(false);
            serverResult.setErr_code("10001");
            serverResult.setMessage("更新接口token错误");
        }
        return serverResult;
    }

    @DeleteMapping(path = "/feed/delete")
    public ServerResult deleteFeed(@RequestHeader("access_token") String accessToken, @RequestBody DeleteBody body) {
        ServerResult serverResult = new ServerResult();
        serverResult.setServer_time(System.currentTimeMillis());
        if ("1234".equals(accessToken)) {
            //删除feed
            serverResult.setSuccess(true);
        } else {
            serverResult.setSuccess(false);
            serverResult.setErr_code("10001");
            serverResult.setMessage("删除接口token错误");
        }
        return serverResult;
    }
}

FileUploadController

package com.jady.retrofitclientserver.controller;

import com.jady.retrofitclientserver.model.DeleteBody;
import com.jady.retrofitclientserver.model.ServerResult;
import com.jady.retrofitclientserver.model.User;
import com.jady.retrofitclientserver.model.UserForLogin;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * Created by lipingfa on 2017/6/16.
 */
@RestController
public class FileUploadController {
    /**
     * 单文件上传
     *
     * @return
     */
    @PostMapping("/file/upload/single")
    public ServerResult uploadFile(@RequestParam("file") MultipartFile file) {

        ServerResult serverResult = new ServerResult<String>();
        serverResult.setServer_time(System.currentTimeMillis());

        if (!file.isEmpty()) {
            try {
                BufferedOutputStream out = new BufferedOutputStream(
                        new FileOutputStream(new File("files/" + file.getOriginalFilename())));
                out.write(file.getBytes());
                out.flush();
                out.close();
                serverResult.setSuccess(true);
            } catch (Exception e) {
                e.printStackTrace();
                serverResult.setSuccess(false);
                serverResult.setErr_code("10010");
                serverResult.setMessage("上传失败:" + e.getMessage());
            }
        } else {
            serverResult.setSuccess(false);
            serverResult.setErr_code("10010");
            serverResult.setMessage("上传失败,文件是空的");
        }
        return serverResult;
    }

    /**
     * 多文件上传
     *
     * @return
     */
    @PostMapping("/file/upload/multiple")
    public ServerResult uploadFiles(HttpServletRequest request) {
        ServerResult serverResult = new ServerResult<String>();
        serverResult.setServer_time(System.currentTimeMillis());

        Map<String, MultipartFile> files = ((MultipartHttpServletRequest) request).getFileMap();
        BufferedOutputStream stream = null;
        for (MultipartFile multipartFile : files.values()) {
            if (!multipartFile.isEmpty()) {
                try {
                    byte[] bytes = multipartFile.getBytes();
                    stream = new BufferedOutputStream(new FileOutputStream(new File("files/" + multipartFile.getOriginalFilename())));
                    stream.write(bytes);
                    stream.close();
                } catch (Exception e) {
                    stream = null;
                    serverResult.setSuccess(false);
                    serverResult.setErr_code("10010");
                    serverResult.setMessage("上传失败:" + e.getMessage());
                    return serverResult;
                }
            } else {
                serverResult.setSuccess(false);
                serverResult.setErr_code("10010");
                serverResult.setMessage("上传失败,文件是空的");
                return serverResult;
            }
        }
        serverResult.setSuccess(true);
        return serverResult;
    }
}

ResourceManager

package com.example.redis.resource.manager;

public class ResourceManager {
    private int count =0;
    private static ResourceManager instance = new ResourceManager();
    private ResourceManager(){}

    public static ResourceManager getInstance(){
        return instance;
    }

    public synchronized void addCount(int i){
        count =count+i;
    }

    public synchronized void minusCount(int i){
        count =count+i;
    }

    public int getCount(){
        return count;
    }

    public void initCount(int i){
        count =i;
    }
}

java springboot初始化udp单播_java_10

java springboot初始化udp单播_java_11

测试

POSTMan进行测试:

查询接口,服务启动,count默认值为0

java springboot初始化udp单播_restful_12


初始化

post:

java springboot初始化udp单播_restful_13


put:

java springboot初始化udp单播_HTTP_14

java springboot初始化udp单播_http_15


java springboot初始化udp单播_restful_16

总结

Postman工作原理

java springboot初始化udp单播_客户端_17


当在postman单机send按钮,服务器将会接受请求并在接口中显示响应

GET
HTTP GET请求方法是从服务器检索数据
数据由唯一的Uri表示
GET请求可以使用“Query String Parameters”将参数传递给服务器
用法:不输入id时,使用默认值