import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class HttpServerV2 {
//1、修改代码格式
//2、解析url中的包含的参数
//3、演示cookie工作流程
private ServerSocket serverSocket = null;
public HttpServerV2(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动");
ExecutorService executorService = Executors.newCachedThreadPool();
while (true) {
Socket clienSocket = serverSocket.accept();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
process(clienSocket);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
private void process(Socket clienSocket) throws IOException {
try {
//1、读取请求并解析
HttpRequest request = HttpRequest.build(clienSocket.getInputStream());
System.out.println("request: "+request);
HttpResponse response = HttpResponse.build(clienSocket.getOutputStream());
//2、根据请求计算响应
response.setHeader("content-type","text/html");
if (request.getUrl().startsWith("/hello")) {
response.setStatus(200);
response.setMessage("OK");
response.writeBody("<h1>hello</h1>");
} else if (request.getUrl().startsWith("/calc")) {
String aStr = request.getParameters("a");
String bStr = request.getParameters("b");
int a = Integer.parseInt(aStr);
int b = Integer.parseInt(bStr);
int result = a + b;
response.setStatus(200);
response.setMessage("OK");
response.writeBody("<h1>result = "+result+"</h1>");
} else if (request.getUrl().startsWith("/cookie")){
response.setStatus(200);
response.setMessage("OK");
response.setHeader("set-cookie","user=yfy time="+ System.currentTimeMillis()/1000);
response.writeBody("<h1>set-cookie</h1>");
} else{
response.setStatus(200);
response.setMessage("OK");
response.writeBody("<h1>default</h1>");
}
//3、把响应写回到客户端
response.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
clienSocket.close();
}
}
public static void main(String[] args) throws IOException {
HttpServerV2 serverV2 = new HttpServerV2(9090);
serverV2.start();
}
}
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
public class HttpResponse {
//表示一个HTTP响应
private String version = "HTTP/1.1";
private int status; //状态码
private String message; //状态码的描述信息
private Map<String,String> headers = new HashMap<>();
private StringBuilder body = new StringBuilder();//方便拼接
//需要把响应写回到客户端时,写到outputStream中去
private OutputStream outputStream = null;
public static HttpResponse build(OutputStream outputStream) {
HttpResponse response = new HttpResponse();
response.outputStream = outputStream;
return response;
}
public void setVersion(String version) {
this.version = version;
}
public void setStatus(int status) {
this.status = status;
}
public void setMessage(String message) {
this.message = message;
}
public void setHeader(String key, String value) {
headers.put(key,value);
}
public void writeBody(String content) {
body.append(content);
}
public void flush() throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(version +" "+ status +" "+ message + "\n");
headers.put("content-Length: " ,body.toString().getBytes().length+"");
for (Map.Entry<String,String> entry : headers.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue()+"\n");
}
bufferedWriter.write("\n");
bufferedWriter.write(body.toString());
bufferedWriter.flush();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class HttpRequest {
private String method;
private String url;
private String version;
private Map<String, String> headers = new HashMap<>();
private Map<String, String> parameters = new HashMap<>();
//请求的构造逻辑,也使用工厂模式
//此处的参数是从socket中获取到的InputStream对象
public static HttpRequest build(InputStream inputStream) throws IOException {
HttpRequest request = new HttpRequest();
//此处的逻辑中,不能把bufferedread写到try中,写进去意味着bufferedreader会被关闭
//影响clientSocket的状态
//等到整个请求处理完了再关闭
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//build的过程就是解析请求的过程
//1、解析首行
String firstLine = bufferedReader.readLine();
String[] firstLineTokens = firstLine.split(" ");
request.method = firstLineTokens[0];
request.url = firstLineTokens[1];
request.version = firstLineTokens[2];
//2、解析url中的参数 /index.html?a=10&b=20
int post = request.url.indexOf("?");
if (post != -1) {
//看看url中是否有?,如果没有说明不带参数,也就不用解析
String parameters = request.url.substring(post+1);//a=10&b=20
parseKV(parameters, request.parameters);
}
//3、解析header
String line = "";
while ((line = bufferedReader.readLine()) != null && line.getBytes().length != 0){
String[] headerTokens = line.split(": ");
request.headers.put(headerTokens[0],headerTokens[1]);
}
//4、解析body
return request;
}
private static void parseKV(String input, Map<String, String> output) {
//按照&切分成若干组键值对
String[] KVTokens = input.split("&");
//按照切分结果再进行=切分
for(String KV : KVTokens) {
String[] result = KV.split("=");
output.put(result[0],result[1]);
}
}
//给这个类构造一些getter方法
//请求的对象是从网络上解析来的,所以不需要setter
public String getMethod() {
return method;
}
public String getUrl() {
return url;
}
public String getVersion() {
return version;
}
public String getHeader (String key) {
return headers.get(key);
}
public String getParameters (String key) {
return parameters.get(key);
}
@Override
public String toString() {
return "HttpRequest{" +
"method='" + method + '\'' +
", url='" + url + '\'' +
", version='" + version + '\'' +
", headers=" + headers +
", parameters=" + parameters +
'}';
}
}