jsp上传到webservice_java利用socket 上传文件到webservice服务器

为提高效率,避免文件IO,本文介绍了如何在Java中直接构造HTTP Post报文,利用Socket连接上传文件到WebService服务器。通过Wireshark抓包分析HTTP报文格式,并分别展示了固定长度和分块传输两种方式的实现,最后提供了一个HttpStream工具类的代码示例。
摘要由CSDN通过智能技术生成

背景

因为业务上的需求,需要将数据传递给第三方,第三方以表单形式接收包含数据的文件,而我方数据存在数据库中,按常规做法,先把数据保存在本地文件,在利用http工具类上传,因为数据行数过多,文件io会大大影响效率,所以决定跳过文件io。

方案

因为HTTP属于应用层协议,所以可以在代码中拼装上传文件的HTTP报文,通过scoket打开TCP连接,写入报文。

过程

首先通过Wireshark抓取环回地址文件上传的HTTP报文:

http.png

然后参照图片中报文的样子拼装http

bufferedWriter.write("POST " + path + " HTTP/1.1\r\n");

bufferedWriter.write("Host: " + "127.0.0.1:8080" + "\r\n");

bufferedWriter.write("content-type: multipart/form-data; boundary=--sugar963sugar\r\n");

bufferedWriter.write("content-length: 10000\r\n");

bufferedWriter.write("\r\n");

bufferedWriter.write("----sugar963sugar\r\n");

bufferedWriter.write("Content-Disposition: form-data; name=\"file\";filename=\"wx.txt\"\r\n");

bufferedWriter.write("Content-type: text/plain\r\n\r\n");

bufferedWriter.write("sdadadadadadada456555cuilvjjf645");

bufferedWriter.write("\r\n----sugar963sugar--\r\n")

拼装好后利用socket请求获取服务器成功响应

但是这个报文有个问题,必须在上传前指定数据长度:content-length: 10000\r\n

当然,可以将这个长度设置成足够业务使用的长度,但为了能够比较通用,避免硬编码,需要换一种传输方式

通过Wireshark抓包发现,http有另外一种动态传输数据的方式:

E6D84http.png

继续照葫芦画瓢:

bufferedWriter.write("POST " + path + " HTTP/1.1\r\n");

bufferedWriter.write("Host: " + "127.0.0.1:8080" + "\r\n");

bufferedWriter.write("content-type: multipart/form-data; boundary=--sugar963sugar\r\n");

bufferedWriter.write("Transfer-Encoding: chunked\r\n");

bufferedWriter.write("\r\n");

bufferedWriter.write("6c\r\n");

bufferedWriter.write("----sugar963sugar\r\n");

bufferedWriter.write("Content-Disposition: form-data; name=\"fi\";filename=\"wx.txt\"\r\n");

bufferedWriter.write("Content-type: text/plain\r\n\r\n\r\n");

bufferedWriter.write("35\r\n");

bufferedWriter.write("sdadadadadadada456555cuilvjjf645");

bufferedWriter.write("\r\n----sugar963sugar--\r\n");

bufferedWriter.write("0\r\n\r\n");

关键的头部信息:Transfer-Encoding: chunked 分块传输

利用socket发送依旧成功获得响应

自此开始编写工具类

结果

package com.example.demo.controller;

import javax.net.ssl.SSLSocketFactory;

import java.io.*;

import java.net.Socket;

import java.util.Arrays;

/**

*

* @author sugar

*

* Created by 2019/01/24

*

*

* */

public class HttpStream {

private Socket socket;

private InputStream inputStream = null;

private OutputStream outputStream = null;

DataMeta dataMeta = DataMeta.FORM;

RequestMothed requestMothed = RequestMothed.POST;

public class Response {

int status;

String msg;

}

public enum RequestMothed {

POST(1);

int value;

RequestMothed(int value) {

this.value = value;

}

}

public enum DataMeta {

FORM(1);

int value;

DataMeta(int value) {

this.value = value;

}

}

public HttpStream(RequestMothed requestMothed, DataMeta dataMeta, String host, int port, boolean isSSL, String path) {

this.dataMeta = dataMeta;

this.requestMothed = requestMothed;

try {

if (isSSL) {

//https请求

socket = (SSLSocketFactory.getDefault()).createSocket(host, port);

inputStream = socket.getInputStream();

outputStream = socket.getOutputStream();

} else {

socket = new Socket(host, port);

inputStream = socket.getInputStream();

outputStream = socket.getOutputStream();

}

if (RequestMothed.POST == requestMothed) {

outputStream.write(("POST " + path + " HTTP/1.1\r\n").getBytes());

outputStream.write(("Host: " + host + ":" + port + "\r\n").getBytes());

outputStream.write(("Connection: keep-alive\r\n").getBytes());

if (DataMeta.FORM == dataMeta) {

outputStream.write(("content-type: multipart/form-data; boundary=--sugar963sugar\r\n").getBytes());

outputStream.write(("Transfer-Encoding: chunked\r\n").getBytes());

outputStream.write(("\r\n").getBytes());

} else {

//其他数据提交方式

}

} else {

//其他请求方式

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public void putData(String key, String value) {

try {

if (RequestMothed.POST == requestMothed) {

if (DataMeta.FORM == dataMeta) {

putDataOfForm(key, value);

} else {

//其他数据提交方式

}

} else {

//其他请求方式

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public void putDataWithFile(String key, String fileName) {

try {

if (RequestMothed.POST == requestMothed) {

if (DataMeta.FORM == dataMeta) {

putDataOfFormWithFile(key, fileName);

} else {

//其他数据提交方式

}

} else {

//其他请求方式

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public void putFileContent(byte[] content, boolean isEnd) {

try {

if (RequestMothed.POST == requestMothed) {

if (DataMeta.FORM == dataMeta) {

putDataFileContent(content, isEnd);

} else {

//其他数据提交方式

}

} else {

//其他请求方式

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public Response Response() throws IOException {

Response response = new Response();

byte[] bytes = new byte[1];

ByteArrayOutputStream byteArray = new ByteArrayOutputStream();

int respL = 0;

while (-1 != inputStream.read(bytes)) {

byteArray.write(bytes);

if (bytes[0] == '\n') {

String context = byteArray.toString();

byteArray.reset();

if (context.equals("\r\n")) break;

else if (context.startsWith("Content-Length: "))

respL = Integer.parseInt(context.substring(16).trim());

else if (context.startsWith("Transfer-Encoding: chunked"))

respL = -1;

else if (context.startsWith("HTTP/1.1 "))

response.status = Integer.parseInt(context.substring(9, 12));

}

}

if (-1 == respL) {

ByteArrayOutputStream bodyByte = new ByteArrayOutputStream();

while (-1 != inputStream.read(bytes)) {

byteArray.write(bytes);

if (bytes[0] == '\n') {

int chunked;

String context = byteArray.toString();

chunked = Integer.parseInt(context.trim(), 16);

byteArray.reset();

if (0 == chunked){

response.msg = bodyByte.toString();

break;

}

byte[] chunkedBody = new byte[chunked];

inputStream.read(chunkedBody);

inputStream.read(new byte[2]);

bodyByte.write(chunkedBody);

}

}

} else {

byte[] body = new byte[respL];

inputStream.read(body);

response.msg = new String(body);

}

return response;

}

public void colse() {

try {

outputStream.close();

inputStream.close();

socket.close();

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public void flush() {

try {

if (RequestMothed.POST == requestMothed) {

if (DataMeta.FORM == dataMeta) {

flushForm();

} else {

//其他数据提交方式

}

} else {

//其他请求方式

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

private void flushForm() throws IOException {

String formM = "----sugar963sugar--";

byte[] bytes = formM.getBytes();

int count = bytes.length;

String countS = Integer.toHexString(count).toLowerCase();

outputStream.write((countS + "\r\n").getBytes());

outputStream.write(bytes);

outputStream.write("\r\n0\r\n\r\n".getBytes());

outputStream.flush();

}

private void putDataOfForm(String key, String value) throws IOException {

String formM = "----sugar963sugar\r\nContent-Disposition: form-data; name=\"" + key + "\"\r\n\r\n" + value + "\r\n";

byte[] bytes = formM.getBytes();

int count = bytes.length;

String countS = Integer.toHexString(count).toLowerCase();

outputStream.write((countS + "\r\n").getBytes());

outputStream.write(bytes);

outputStream.write("\r\n".getBytes());

}

private void putDataOfFormWithFile(String key, String fileName) throws IOException {

String formM = "----sugar963sugar\r\nContent-Disposition: form-data; name=\"" + key + "\";filename=\"" + fileName + "\"\r\nContent-type: text/plain\r\n\r\n";

byte[] bytes = formM.getBytes();

int count = bytes.length;

String countS = Integer.toHexString(count).toLowerCase();

outputStream.write((countS + "\r\n").getBytes());

outputStream.write(bytes);

outputStream.write("\r\n".getBytes());

}

private void putDataFileContent(byte[] content, boolean isEnd) throws IOException {

byte[] contentE = content;

if (isEnd) {

contentE = Arrays.copyOf(content, content.length + 2);

contentE[content.length] = '\r';

contentE[content.length + 1] = '\n';

}

int count = contentE.length;

String countS = Integer.toHexString(count).toLowerCase();

outputStream.write((countS + "\r\n").getBytes());

outputStream.write(contentE);

outputStream.write("\r\n".getBytes());

}

}

利用putDataWithFile和putFileContent可以将文件内容直接写入报文,目前只实现了POST表单提交信息,后期再进行扩充

测试demo:

HttpStream httpStream = new HttpStream(HttpStream.RequestMothed.POST, HttpStream.DataMeta.FORM, "127.0.0.1", 8080, false, "/file/t");

httpStream.putData("api_p","aa22");

httpStream.putDataWithFile("file", "fileName.txt");

httpStream.putFileContent("hah邪恶那大家阿卡\n".getBytes(), false);

httpStream.putFileContent("ddddee".getBytes(), true);

httpStream.putData("f1","0");

httpStream.flush();

HttpStream.Response response = httpStream.Response();

System.out.println(response.status + ":" + response.msg);

httpStream.colse();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值