直接上代码,涉及http消息格式问题参考其他资料
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by chao.zeng on 2016/5/30.
*/
public class HttpClient {
private Socket socket;
private StringBuilder header=new StringBuilder();
private List<StringBuilder> bodys=new ArrayList<StringBuilder>();
private List<StringBuilder> bodyHeadersFile=new ArrayList<StringBuilder>();
private long contentLength=0;
private String boundary="----WebKitFormBoundaryUalLNdJ5BjmXlLhv";
public static void main(String[] args) throws IOException {
HttpClient client=new HttpClient("localhost",8080);
Map<String,String> params=new HashMap<String,String>();
params.put("id","10030");
params.put("xx","xxoo");
Map<String,String> files=new HashMap<String,String>();
files.put("name1","d:\\deerway.zip");
files.put("name2","d:\\deerway2.zip");
client.upload("/cloudolp.dc/deviceApi/cameraupload",params,files);
Map<String,String> params2=new HashMap<String,String>();
params2.put("id","10030");
params2.put("name","name1");
client=new HttpClient("localhost",8080);
client.download("/cloudolp.dc/deviceApi/cameradownload",params2,"d:\\xx.zip");
}
public HttpClient(String host,int port) throws IOException {
socket=new Socket(host,port);
}
private void setHeader(){
/**
* 写入请求行
* 第一个参数为方法,POST,GET等
* 第二个是URL地址
* 第三个是HTTP版本,有HTTP/1.0,HTTP/1.1,HTTP/2.0,
*/
header.append("POST /cloudolp.dc/deviceApi/cameraupload HTTP/1.1\r\n");
/**
* 写入请求头,请求头和请求体之间需要一行空行分割
* Host:参数必须要有,不然服务器不接收
* Content-Type:因为是上传文件,此值必须为multipart/form-data,后面的boundary是各个请求体参数的分割符,详情参考http规范
* 每个头和体之间要有空行分隔'\r\n'
*/
header.append("Host: localhost:8088\r\n");
header.append("Connection:Keep-Alive\r\n");
header.append("Content-Length:"+contentLength+"\r\n");
header.append("Content-Type:multipart/form-data; boundary="+boundary+"\r\n");
header.append("\r\n");
}
public void upload(String url,Map<String,String> params,Map<String,String> files) throws IOException {
/**
* 计算消息体长度,因为消息头需要传Content-Length,即消息体长度
* 因为是multipart/form-data,所以消息体会包含很多部分,每部分用分割符boundary分开(其实是两个'-'加上头上定义的分隔符)
*/
/**
* 普通参数
*/
for(Map.Entry<String,String> entry:params.entrySet()){
StringBuilder body=new StringBuilder();
body.append("--"+boundary+"\r\n");
body.append("Content-Disposition: form-data; name=\""+entry.getKey()+"\"\r\n");
body.append("\r\n");
body.append(entry.getValue());
body.append("\r\n");
bodys.add(body);
contentLength+=body.toString().getBytes().length;
}
/**
* 文件参数
*/
for(Map.Entry<String,String> entry:files.entrySet()){
StringBuilder bodyheader=new StringBuilder();
bodyheader.append("--"+boundary+"\r\n");
bodyheader.append("Content-Disposition: form-data; name=\""+entry.getKey()+"\"; filename=\""+entry.getValue()+"\"\r\n");
bodyheader.append("\r\n");
bodyHeadersFile.add(bodyheader);
contentLength+=bodyheader.toString().getBytes().length;
File file=new File(entry.getValue());
contentLength+=file.length()+2;
}
StringBuilder endboundary=new StringBuilder();
endboundary.append("--");
endboundary.append(boundary);
endboundary.append("--"+"\r\n");
contentLength+=endboundary.toString().getBytes().length;
setHeader();
OutputStream out=socket.getOutputStream();
out.write(header.toString().getBytes());
for(StringBuilder body:bodys){
out.write(body.toString().getBytes());
}
int i=0;
for(Map.Entry<String,String> entry:files.entrySet()){
out.write(bodyHeadersFile.get(i++).toString().getBytes());//写入文件头
File file=new File(entry.getValue());
//写入文件
InputStream input=new FileInputStream(file);
byte[] bs=new byte[8192];
int length=input.read(bs);
while(length!=-1){
out.write(bs,0,length);
length=input.read(bs);
}
out.write("\r\n".getBytes());//写入空行
}
//写入结束标志
out.write(endboundary.toString().getBytes());
}
public void download(String url,Map<String,String> params,String dest) throws IOException {
StringBuilder urlsb=new StringBuilder();
urlsb.append(url);
urlsb.append("?");
for(Map.Entry<String,String> entry:params.entrySet()){
urlsb.append(entry.getKey());
urlsb.append("=");
urlsb.append(entry.getValue());
urlsb.append("&");
}
urlsb.deleteCharAt(urlsb.length()-1);
StringBuilder sb=new StringBuilder();
sb.append("GET "+urlsb.toString()+" HTTP/1.1\r\n");
sb.append("Host: localhost:8088\r\n");
sb.append("Connection:Keep-Alive\r\n");
sb.append("\r\n");
socket.getOutputStream().write(sb.toString().getBytes());
InputStream input=socket.getInputStream();
String line=readLine(input);
//第一行为响应行,包含状态码
String[] reslines=line.split(" ");
if(!reslines[1].equals("200")){
System.out.println("响应出错:状态码为"+reslines[1]);
return;
}
while(!line.equals("")){
System.out.println(line);
line=readLine(input);
}
OutputStream out=new FileOutputStream(dest);
int length=Integer.parseInt(readLine(input),16);
while(length!=0){
byte[] content=new byte[length];
input.read(content);
out.write(content,0,length);
input.read();//读入'\r'
input.read();//读入'\n'
length=Integer.parseInt(readLine(input),16);
}
}
private String readLine(InputStream input) throws IOException {
StringBuilder sb=new StringBuilder();
char c=(char)input.read();
while(c!='\r'){
sb.append(c);
c=(char)input.read();
}
input.read();
return sb.toString();
}
}