HTTP请求方式和报文解析
- 作者 firedragonpzy
- 23 四月, 2020
- 暂无评论
Software MyZone:66202765(群号,欢迎加入,若满,请加1群)
Software MyZone 1群(2dx):286504621
Software MyZone 2群(山东):204954191
Software MyZone【Java群】:162865493
【加群请写:Software MyZone或者是firedragonpzy】
淘宝店:【58买单】初次开店,大家多多支持……
群论坛:【火龙论坛】正试运营阶段,欢迎大家多提些建设性意见……
我的digitalocean推广链接:https://www.digitalocean.com/?refcode=65dfdb158f1a,Everyone you refer gets $10 in credit,从此链接注册,你将获得10美元。
一、概述
最近想尝试写一个关于网络请求的系列文章,将网络请求的基础、使用及网络框架的学习分析总结以下,大致准备从以下几个方面分析:
网络请求的基础
HTTP请求方式和报文解析
Cookie 和 Session的理解与使用
HTTP Cache缓存机制
封装网络请求
TCP 和 Socket
二、HTTP请求方式
HTTP提供了七种请求方式:GET、POST、DELETE、PUT、HEAD、TRACE、OPTIONS,其中PUT,DELETE、POST、GET分别对应了资源的增、删、改、查,也是使用最多的请求方式;
GET
GET请求报文 和 服务器的响应报文
上述请求的资源是www.devtf.cn/articles/123.html文件,GET请求是将请求参数放在URL之后,第一个参数之前使用“?“,之后的参数格式为:参数名=参数值,参数名之间使用”&“连接,如:www.devtf.cn/articles/123.html?username=myname&userid=123
POST
POST请求通常是使用来提交HTML的表单,表单中的数据传输到服务器,由服务器对这些数据处理,请求和响应的报文如下:
PUT
与GET从服务器获取数据相反的是,PUT是想服务器写入资源,比如像CSDN这样允许用户创建Web页面,并用PUT直接传输到服务器上,返回服务器上的资源地址;
DELETE
使用方法和GET一样,请求删除URL指定的资源文件
三、HTTP请求报文
HTTP的请求报文由请求行(Request line)、请求头部(Header)空行和请求数据;
请求行:请求报文的第一行,用来说明以什么方式请求、请求的地址和HTTP版本
头部字段:每个头部字段都包含一个名字和值,二者之间采用“:”连接,如:Connection:Keep-Alive
请求数据:请求的主体根据不同的请求方式请求主体不同
GET、DELETE
这两种请求报文比较简单,查看上面即可
POST、PUT
POST和PUT的请求行和请求头部,在上述已经列出,现在主要介绍请求报文中的参数:
一个参数的开始是由“–”加上boundary开始的
然后加上参数的Header信息,格式为字段名和字段值,二者之间使用“:”连接,如:Content-Type:text/plain
加上一个空行
发送的参数值
请求的数据以“–”+boundary+“–”结束真个请求的报文结束符
四、HTTP响应报文
HTTP的响应报文为3个部分组成:状态行、消息报文、响应正文
状态行:由HTTP版本、响应状态码、响应状态描述;如:HTTP/1.1 200 OK
响应报文头部:使用关键字和值表示,二者使用“:”隔开;如:Content-Type:text/html
响应内容:请求空行之后就是请求内容
常见的状态码和描述
200 OK : 客户端请求成功
400 Bad Request:客户端请求语法错误,服务器无法解析
401 Unauthorized:请求未经授权
403 Forbidden:服务器收到请求拒绝服务
404 Not Found:请求资源不存在,常见URL错误
500 Internal Server Error:服务端不可预期错误
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() }
运行后输出信息
————————————————
版权声明:本文为CSDN博主「Alex@W」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/alexwll/article/details/82287737