当前位置:首页 > 服务端 > HTTP请求方式和报文解析

HTTP请求方式和报文解析

2022年11月10日 11:51:01服务端31

一、概述

最近想尝试写一个关于网络请求的系列文章,将网络请求的基础、使用及网络框架的学习分析总结以下,大致准备从以下几个方面分析:

  1. 网络请求的基础
  2. HTTP请求方式和报文解析
  3. Cookie 和 Session的理解与使用
  4. HTTP Cache缓存机制
  5. 封装网络请求
  6. TCP 和 Socket

二、HTTP请求方式

HTTP提供了七种请求方式:GET、POST、DELETE、PUT、HEAD、TRACE、OPTIONS,其中PUT,DELETE、POST、GET分别对应了资源的增、删、改、查,也是使用最多的请求方式;

  • GET
  1. GET请求报文 和 服务器的响应报文

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记    HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

上述请求的资源是www.devtf.cn/articles/123.html文件,GET请求是将请求参数放在URL之后,第一个参数之前使用““,之后的参数格式为:参数名=参数值,参数名之间使用”&“连接,如:www.devtf.cn/articles/123.html?username=myname&userid=123

  • POST

POST请求通常是使用来提交HTML的表单,表单中的数据传输到服务器,由服务器对这些数据处理,请求和响应的报文如下:

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

  • PUT

与GET从服务器获取数据相反的是,PUT是想服务器写入资源,比如像CSDN这样允许用户创建Web页面,并用PUT直接传输到服务器上,返回服务器上的资源地址;

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

  • DELETE

使用方法和GET一样,请求删除URL指定的资源文件

三、HTTP请求报文

HTTP的请求报文由请求行(Request line)、请求头部(Header)空行和请求数据;

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

  1. 请求行:请求报文的第一行,用来说明以什么方式请求、请求的地址和HTTP版本
  2. 头部字段:每个头部字段都包含一个名字和值,二者之间采用“:”连接,如:Connection:Keep-Alive
  3. 请求数据:请求的主体根据不同的请求方式请求主体不同
  • GET、DELETE

这两种请求报文比较简单,查看上面即可

  • POST、PUT

POST和PUT的请求行和请求头部,在上述已经列出,现在主要介绍请求报文中的参数:

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

  1. 一个参数的开始是由“--”加上boundary开始的
  2. 然后加上参数的Header信息,格式为字段名和字段值,二者之间使用“:”连接,如:Content-Type:text/plain
  3. 加上一个空行
  4. 发送的参数值
  5. 请求的数据以“--”+boundary+“--”结束真个请求的报文结束符

四、HTTP响应报文

HTTP的响应报文为3个部分组成:状态行、消息报文、响应正文

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

  1. 状态行:由HTTP版本、响应状态码、响应状态描述;如:HTTP/1.1 200 OK
  2. 响应报文头部:使用关键字和值表示,二者使用“:”隔开;如:Content-Type:text/html
  3. 响应内容:请求空行之后就是请求内容
  • 常见的状态码和描述
  1. 200  OK : 客户端请求成功
  2. 400  Bad Request:客户端请求语法错误,服务器无法解析
  3. 401  Unauthorized:请求未经授权
  4. 403  Forbidden:服务器收到请求拒绝服务
  5. 404  Not Found:请求资源不存在,常见URL错误
  6. 500  Internal Server Error:服务端不可预期错误
  7. 503  Server Unavailable:服务器当前不能处理客户端请求

五、简单模拟HTTP服务器

  • 创建HttpServer:内部创建ServerSocket监听客户端的输出信息
public const val HTTP_PORT = 8080  // 监听的端口
class HttpServiceSocket : Thread() {

    val mServiceSocket by lazy {
        ServerSocket(HTTP_PORT)   // 创建ServerSocket
    }

    override fun run() {
        while (true){
            Log.d("HttpServiceSocket","Service 等待输入...")
            DeliverThread(mServiceSocket.accept()).start() //开启线程接收信息
    }

    }
  • 为了不阻塞线程,再开辟新线程从输入流中读取数据
class DeliverThread(val socket: Socket) : Thread() {

    val bufferedReader by lazy {
        BufferedReader(InputStreamReader(socket.getInputStream()))
    }

    val printStream by lazy {
        PrintStream(socket.getOutputStream())
    }

    val headerParamsMap = mutableMapOf<String,String>() // 储存Header的参数信息
    val paramsMap = mutableMapOf<String,String>() // 储存参数的参数信息


    lateinit var httpMethod : String
    lateinit var subPath : String
    lateinit var boundary : String
    var isParseHeader = false

    override fun run() {
        super.run()
        parseRequest() // 解析Request
        handlerResult()  // 构建返回的Response
        bufferedReader.close()
        printStream.close()
        socket.close()
    }
}
  • 解析Request:parseRequest()
 private fun parseRequest() {
        var line = 1
        var lineString : String? = bufferedReader.readLine()

        while (lineString != null){
            if (line == 1){
                parseRequestLine(lineString)// 解析请求行
            }
            if (line != 1 && !isParseHeader){
                parserHeader(lineString)  // 解析请求头部
            }
            if (isParseHeader){
                parseParams(lineString) // 解析参数
            }

            lineString = bufferedReader.readLine()  //循环读取数据
            line++
        }
    }

  • 解析请求行、请求头部、请求参数
// 解析请求行
  private fun parseRequestLine(lineString: String) {
        val strings = lineString.split(" ")
        Log.d("Http Method",strings[0])
        Log.d("Http Path",strings[1])
        Log.d("Http Version",strings[2])
    }

// 解析请求头部
 private fun parserHeader(lineString: String) {
        if (lineString == ""){
            isParseHeader = true
            Log.d("Http Request","-------Header 解析完成 -------")
            return
        }else if (lineString.contains("boundary")){
            boundary = parseBoundary(lineString)
            Log.d("Http Request","boundary=$boundary")
        }else{
            val strings = lineString.split(":")
            headerParamsMap[strings[0]] = strings[1]
            Log.d("Http Content","${strings[0] .trim()}  :  ${strings[1] .trim()}")
        }
    }

private fun parseBoundary(lineString: String): String {
        val strings = lineString.split(";")
        parserHeader(strings[0])
        if (strings[1] != null){
            return strings[1].split("=")[1]
        }
        return ""
    }

private fun parseParams(lineString: String) {
        if (lineString == "--$boundary"){
            Log.d("Http Content",lineString)
            parseParamsType()
        }
    }

    private fun parseParamsType() {
        val stringParams = bufferedReader.readLine()
        Log.d("Http Content",stringParams)
        val name = parseBoundary(stringParams)
        bufferedReader.readLine()
        val value = bufferedReader.readLine()
        paramsMap[name] = value
        Log.d("Http Content"," ")
        Log.d("Http Content","$value")
    }
  • 模拟POST请求
class HttpPost(var url:String)  {
    private lateinit var mSocket: Socket  // 创建Socket
    val  paramsMap = mutableMapOf<String,String>()  // 储存设置的信息
    fun add(name : String, value : String){  // 添加参数
        paramsMap[name] = value
    }
    fun execute(){
        mSocket = Socket(url, HTTP_PORT)
        val printStream = PrintStream(mSocket.getOutputStream())
        val bufferedReader = BufferedReader(InputStreamReader(mSocket.getInputStream()))
        val boundary = "http_boundary_123"
        writeHead(boundary,printStream)
        writeParams(boundary,printStream)
        writeResponse(bufferedReader)
    }

// 输出返回的Response
    private fun writeResponse(bufferedReader: BufferedReader) {
        Log.d("Http Response","请求结果...")
        Thread{
            var string = bufferedReader.readLine()
            while (string == null || !string.contains("HTTP")){
                string = bufferedReader.readLine()
            }
            while (string != null){
                Log.d("Http Response",string)
                string = bufferedReader.readLine()
            }
        }.start()

    }

// 写入参数
    private fun writeParams(boundary: String, printStream: PrintStream) {
        var iterator = paramsMap.keys.iterator()
        while (iterator.hasNext()){
            val name = iterator.next()
            printStream.println("--$boundary")
            printStream.println("Content-Disposition: from-data; name=$name")
            printStream.println()
            printStream.println(paramsMap.get(name))
        }
        printStream.println("--$boundary--")
    }
//写入请求头部
    private fun writeHead(boundary: String, printStream: PrintStream) {
        printStream.println("POST /api/login/ HTTP/1.1")
        printStream.println("content-length:123")
        printStream.println("Host:$url:$HTTP_PORT")
        printStream.println("Content-Type:multipart/from-data;boundary=$boundary")
        printStream.println("User-Agent:android")
        printStream.println()
    }
}
  • 启动ServerSocket并发送请求信息
btnService.setOnClickListener { HttpServiceSocket().start() }

        btnPost.setOnClickListener {
            Thread {
                val httpPost = HttpPost("127.0.0.1")
                httpPost.add("userName","Simple")
                httpPost.add("pwd","pwd_123")
                httpPost.execute()
            }.start()
        }
  • 运行后输出信息

HTTP请求方式和报文解析 _ JavaClub全栈架构师技术笔记

 

作者:Alex@W
来源链接:https://blog.csdn.net/Alexwll/article/details/82287737

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/server/69252.html

标签: HTTP
分享给朋友: