http数据包格式及Java模拟http客户端发请求
- 不管什么请求请求头后面都要有两个\n换行
- get请求的请求头Content-Length不为0时,请求数据包和POST差不多
- post请求注意请求头Content-Length为body的长度
- java socket发送和接收必须时不同的线程
- 如果想单方面关闭输入输出流,使用socket对象关闭,因为单独关闭输入流或输出流都会造成socker关闭,如单方面关闭输出流用
socket.shutdownOutput();
- 如果想继续请求需要自行处理http响应结束,如果按字节读取结束标志为
\r\n0\r\n\r\n,使用BufferedReader的readLine时,判断连续两行是否按顺序分别为0和"",是则结束
http数据包格式
模拟get响应
[2024-05-30 14:48:51.170]# RECV ASCII FROM :58790>
GET /a HTTP/1.1
Host: 192.168.10.153:8080
Connection: keep-alive
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
cache-control: max-age=0
accept-language: zh-CN,zh;q=0.9
upgrade-insecure-requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
Referer: http://192.168.10.153:8080/a
Accept-Encoding: gzip, deflate
[2024-05-30 14:48:52.996]# SEND ASCII TO ALL>
HTTP/1.1 200
Content-Type: application/json
Content-Length: 111
Date: Thu, 22 Dec 2022 01:50:15 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{"senid":"c3135f2edcec457c966a515688fff3e3","nonce":"587056045","timestamp":"1671623839","appkey":"SD63236305"}
模拟get请求
[2022-12-22 09:50:15.918]# SEND ASCII>
GET /my/t1?senid=c3135f2edcec457c966a515688fff3e3&nonce=587056045×tamp=1671623839&appkey=SD63236305 HTTP/1.1
X-Nuonuo-Sign: tqpRd6s11B8msPGRN0FTMU3KJlY=
method: nuonuo.OpeMplatform.requestBillingNew
sdkVer: 1.0.5.2
userTax: 339902999999789113
accessToken:
Content-Length: 0
Host: 192.168.10.153:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_321)
Accept-Encoding: gzip,deflate
[2022-12-22 10:09:22.779]# RECV ASCII>
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 22 Dec 2022 02:09:22 GMT
Keep-Alive: timeout=60
Connection: keep-alive
6f
{"senid":"c3135f2edcec457c966a515688fff3e3","nonce":"587056045","timestamp":"1671623839","appkey":"SD63236305"}
0
![get请求数据包]()
模拟post请求
[2022-12-22 09:50:15.918]# SEND ASCII>
POST /my/t2?senid=c3135f2edcec457c966a515688fff3e3&nonce=587056045×tamp=1671623839&appkey=SD63236305 HTTP/1.1
X-Nuonuo-Sign: tqpRd6s11B8msPGRN0FTMU3KJlY=
method: nuonuo.OpeMplatform.requestBillingNew
sdkVer: 1.0.5.2
userTax: 339902999999789113
accessToken:
Content-Type: application/json
Content-Length: 16
Host: 192.168.10.153:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_321)
Accept-Encoding: gzip,deflate
{"order":"name"}
[2022-12-22 09:50:15.931]# RECV ASCII>
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 22 Dec 2022 01:50:15 GMT
Keep-Alive: timeout=60
Connection: keep-alive
6f
{"senid":"c3135f2edcec457c966a515688fff3e3","nonce":"587056045","timestamp":"1671623839","appkey":"SD63236305"}
0
![http接口]()
![post请求数据包]()
源码
package me.muphy.web;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class MyTest {
public static void main(String[] args) {
Socket socket = new Socket();
String send = "POST /my/t2?senid=c3135f2edcec457c966a515688fff3e3&nonce=587056045×tamp=1671623839&appkey=SD63236305 HTTP/1.1\n" +
"X-Nuonuo-Sign: tqpRd6s11B8msPGRN0FTMU3KJlY=\n" +
"method: nuonuo.OpeMplatform.requestBillingNew\n" +
"sdkVer: 1.0.5.2\n" +
"userTax: 339902999999789113\n" +
"accessToken: \n" +
"Content-Type: application/json\n" +
"Content-Length: 16\n" +
"Host: 192.168.10.153:8080\n" +
"Connection: Keep-Alive\n" +
"User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_321)\n" +
"Accept-Encoding: gzip,deflate\n" +
"\n" +
"{\"order\":\"name\"}";
try {
socket.connect(new InetSocketAddress(8080));
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();
// 读取线程
new Thread(() -> {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
boolean end = false;
String line;
while ((line = reader.readLine()) != null) {
if ("0".equals(line)) {
end = true;
} else if (line.isEmpty() && end) {
break;
} else {
end = false;
}
sb.append("\n");
sb.append(line);
}
if (sb.length() > 0) {
sb.delete(0, 1);
System.out.println("接收数据:");
System.out.println(sb);
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
// 发送数据
System.out.println("发送数据:");
System.out.println(send);
System.out.println();
try {
outputStream.write(send.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
![执行结果]()