直接上代碼,涉及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();
}
}