需要先了解一下HTTP的协议格式

http请求
- 首行:[方法] + [url] + 版本
- Header:请求的属性,冒号分割的键值对;每组属性用\n结尾,遇到空行部分表示header结束
- Body:空行的后面的部分全是body,如果body存在,再Header中会有一个Content-length属性来标识body的长度
http响应
- 首行:[版本号] + [状态码] + [状态码解释]
- Header:请求的属性,冒号分割的键值对;每组属性用\n结尾,遇到空行部分表示header结束
- Body:空行的后面的部分全是body,如果body存在,再Header中会有一个Content-length属性来标识body的长度
http常见的header
- Content-Type: 数据类型(text/html等)
- Content-Length: Body的长度
- Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上
- User-Agent: 声明用户的操作系统和浏览器版本信息;
- referer: 当前页面是从哪个页面跳转过来的
- Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyServer {
private static final int PORT = 9999;//端口号
private static final String CHARSET = "UTF-8"; //统一的字符集编码
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);//监听的socket
ExecutorService poll = Executors.newFixedThreadPool(10);//创建一个10线程的线程池
while (true){
Socket socket = serverSocket.accept();
poll.submit(new Runnable() {
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//解析http请求行
String httpLine = reader.readLine();//这个就是读了一行
System.out.println("=====" + httpLine);
String[] httpLineArray = httpLine.split(" ");
String requestMethod = httpLineArray[0];
String requesturl = httpLineArray[1];
String requestVersion = httpLineArray[2];
//解析请求头
String requestHeader;
Map<String,String> headers = new HashMap<>();
while ((requestHeader = reader.readLine()) != null && requestHeader.length() != 0){
String headArray[] = requestHeader.split(":");
headers.put(headArray[0].trim(),headArray[1].trim());
}
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),CHARSET),true);
String content;
if ("/307".equals(requesturl)){
writer.println("HTTP/1.1 307 Temporary Redirect");
writer.println("Location: http://www.bit.edu.vip");
content = "跳转了";
}else if ("/404".equals(requesturl)){
writer.println("HTTP/1.1 404 Not Found");
content = "<h1>没有找到资源</h1>";
}else {
writer.println("HTTP/1.1 200 OK");
content = "<h1> 我的sever服务器</h1>";
}
writer.println("Content-Type: text/html;charset=utf-8");
writer.println("Content-Length: " + content.getBytes(CHARSET).length);
writer.println();//这是空行
writer.println(content.toString());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
Session And Cookie
- Http是一个无状态协议,就是说这一次请求和上一次请求是没有联系的,互不认识没有关联的.这种无状态的好处是快速.坏处是需要进行用户状态保持的场景时,必须使用一些方式或者手段
- http是一个无状态的协议,但是访问有些资源的时候往往需要经过认证的用户才能访问,而且需要一直保持在线状态,所以cookie是一种在游览器端解决的方案,将登录认证之后的用户信息保存在本地游览器中,后面每次发起http请求,都会自动携带上该信息,就能到达认证用户,保持用户在线的作用.
设置cookie的方法在http的Response报头可以携带Set-Cookie字段来完成

Session
- 将用户信息保存到本地浏览器中,能解决一定的问题,但是又引进了新的安全问题,一旦Cookie丢失,用户信息泄漏,所以有了另外一种解决方法,将用户敏感信息保存到服务器,而服务器本身采用md5算法或相关算法生成唯一值,而该值保存到客户端浏览器,随后客户端的后续请求,浏览器都会自动携带该id,进而再服务器端认证,达到状态保持的效果.
(http请求 + Cookie(带session - id))
Session VS Cookie
两者有什么区别呢
Cookie 是以文本文件格式存储在浏览器(客户端)中,而Session存储在服务器
因为每次发送http请求,都要携带有效Cookie信息,所以Cookie一般有大小限制,以防止网络压力,一般不超过4k
可以轻松访问cookie值,但是我们无法轻松访问会话值,因此session方案更安全
带Set-Cookie
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SetCookieServer {
private static final int PORT = 9999;
private static final String CHARSET = "UTF-8";
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
ExecutorService pool = Executors.newCachedThreadPool();
while (true){
Socket socket = serverSocket.accept();
pool.submit(new Runnable() {
@Override
public void run() {
try {
Request request = Request.build(socket.getInputStream());
Response response = Response.build(socket.getOutputStream());
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),CHARSET),true);
if ("/307".equals(request.getUri())){
response.setStatus(307);
response.setMessage("Temporary Redirect");
response.addHeaders("Location","http//www.bitedu.vip");
response.println("");
}else if ("/404".equals(request.getUri())){
response.setStatus(404);
response.setMessage("Not Found");
response.println("<h1>没有找到资源</h1>");
}else if("/setCookie".equals(request.getUri())) {
response.setStatus(200);
response.setMessage("OK");
response.addHeaders("Set-Cookie", "studentid=" + UUID.randomUUID());
response.println("<h1>Set Cookie OK</h1>");
}else {
response.setStatus(200);
response.setMessage("OK");
response.println("<h1>My Http Server</h1>");
}
response.flush();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
class Request{
private String method;//请求方法
private String uri;//请求路径
private String version;//请求版本
private Map<String,String> headers = new HashMap<>();//请求头
private Map<String,String> parameters = new HashMap<>();//请求
public void setMethod(String method) {
this.method = method;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getMethod() {
return method;
}
public String getUri() {
return uri;
}
public String getVersion() {
return version;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setVersion(String version) {
this.version = version;
}
private static final String CHARSET = "UTF-8";
private Request(){}
/**
* 解析http 请求并生成请求对象
* @param is http http请求流
* @return 请求对象
* Throw IO Exception
*/
public static Request build(InputStream is)throws IOException {
Request request = new Request();
BufferedReader reader = new BufferedReader(new InputStreamReader(is,CHARSET));
//处理请求行
String[] requestLineArray = reader.readLine().split(" ");
request.setMethod(requestLineArray[0]);
request.setUri(requestLineArray[1]);
request.setVersion(requestLineArray[2]);
//处理请求头
String requestHeader;
while ((requestHeader = reader.readLine()) != null && requestHeader.length() != 0){
String[] headArray = requestHeader.split(":");
request.addHeader(headArray[0].trim(),headArray[1].trim());
}
return request;
}
public void addHeader(String key,String value){
headers.put(key,value);
}
@Override
public String toString() {
return "Request{" +
"method='" + method + '\'' +
", uri='" + uri + '\'' +
", version='" + version + '\'' +
", headers=" + headers +
", parameters=" + parameters +
'}';
}
}
class Response{
private int status;//响应状态码
private String message;//响应状态
private Map<String,String> responseHeaders = new HashMap<>();//响应
private PrintWriter writer;//响应输出流
private static final String CHARSET = "UTF-8";
private StringBuilder body = new StringBuilder();
private Response(){}
public static Response build(OutputStream os) throws UnsupportedEncodingException {
Response response = new Response();
response.writer = new PrintWriter(new OutputStreamWriter(os,CHARSET),true);
return response;
}
//返回信息
public Response println(String content){
body.append(content + "\r\n");
return this;
}
public void flush() throws IOException {
writer.println("HTTP/1.1 " + status + " " + message);
writer.println("Content-Type: text/html;charset=utf-8");
writer.println("Content-Length: " + body.toString().getBytes(CHARSET).length);
responseHeaders.forEach((k,v)->{ writer.println(k+": "+v); });
writer.println();
writer.println(body.toString());
}
public void addHeaders(String key,String value){
responseHeaders.put(key,value);
}
public void setStatus(int status) {
this.status = status;
}
public void setMessage(String message) {
this.message = message;
}
public void setResponseHeaders(Map<String, String> responseHeaders) {
this.responseHeaders = responseHeaders;
}
public void setWriter(PrintWriter writer) {
this.writer = writer;
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
public Map<String, String> getResponseHeaders() {
return responseHeaders;
}
public PrintWriter getWriter() {
return writer;
}
}
HTTPServer + sessionID + html
package HTTP;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Request1{
private String method;
private String uri;
private String version;
private Map<String,String> headers = new HashMap<>();//请求头
/*
请求参数
*/
private Map<String,String> parameters = new HashMap<>();
private Map<String,String> cookie = new HashMap<>();
private static final String CHARSET = "UTF-8";
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
private Request1(){}
public static Request1 build(InputStream is) throws IOException{
Request1 request = new Request1();
BufferedReader reader = new BufferedReader(new InputStreamReader(is,CHARSET));
String line = reader.readLine();
System.out.println("请求行: " + line);
//处理请求行
if (line != null ){
String[] requestLineArray = line.split(" ");
request.setMethod(requestLineArray[0]);
request.setUri(requestLineArray[1]);
request.setVersion(requestLineArray[2]);
}
//处理请求头
while ((line = reader.readLine()) != null && line.length() != 0){
System.out.println("请求头: " + line);
String headerArray[] = line.split(":");
request.addHeader(headerArray[0].trim(),headerArray[1].trim());
if ("Cookie".equalsIgnoreCase(headerArray[0].trim())){
String[] cookies = headerArray[1].trim().split(";");
for (String cookie : cookies){
String[] cookieArray = cookie.split("=");
request.cookie.put(cookieArray[0].trim(),cookieArray[1].trim());
}
}
}
//处理请求体
if ("POST".equals(request.getMethod())){
int len = Integer.parseInt(request.getHeaders("Content-Length"));
char[] chars = new char[len];
reader.read(chars,0,len);
System.out.println("请求体: " + String.valueOf(chars));
for (String requestParam : String.valueOf(chars).split("&")){
String[] paramArray = requestParam.split("=");
request.addParameter(paramArray[0],paramArray[1]);
}
}
return request;
}
private void addParameter(String key, String value) {
parameters.put(key,value);
}
private String getHeaders(String s) {
return headers.get(s);
}
private void addHeader(String key, String value) {
headers.put(key,value);
}
@Override
public String toString() {
return "Request1{" +
"method='" + method + '\'' +
", uri='" + uri + '\'' +
", version='" + version + '\'' +
", headers=" + headers +
", parameters=" + parameters +
", cookie=" + cookie +
'}';
}
public String getParameters(String key) {
return parameters.get(key);
}
public String getCookie(String key) {
return cookie.get(key);
}
}
class Response1{
private int status;
private String message;
private Map<String,String> headers = new HashMap<>();//响应头
private PrintWriter writer;//打印流
private static final String CHARSET = "UTF-8";
private StringBuffer body = new StringBuffer();
private Response1(){}
public static Response1 build(OutputStream os) throws UnsupportedEncodingException {
Response1 response = new Response1();
response.writer = new PrintWriter(new OutputStreamWriter(os,CHARSET),true);
return response;
}
/**
* 返回信息
*/
public Response1 printlin(String content){
body.append(content + "\r\n");
return this;
}
public void flush() throws IOException{
writer.println("HTTP/1.1 " + status + " " + message);
writer.println("Content-Type: text/html;charset=utf-8");
writer.println("Content-Length: " + body.toString().getBytes(CHARSET).length);
headers.forEach((k,v)->{
writer.println(k+": " + v);
});
writer.println();
writer.println(body.toString());
}
public void addheader(String key,String value){
headers.put(key,value);
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
}
public class MyServer {
private static final int PORT = 8888;
private static final Map<String, Object> SESSION = new HashMap<>();
private static final String CHARSET = "UTF-8";
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
ExecutorService pool = Executors.newFixedThreadPool(10);
try {
while (true){
Socket socket = serverSocket.accept();
pool.submit(new Runnable() {
@Override
public void run() {
try {
Request1 request = Request1.build(socket.getInputStream());
Response1 response = Response1.build(socket.getOutputStream());
if ("/307".equals(request.getUri())){
response.setStatus(307);
response.setMessage("Temporary Redirect");
response.addheader("Location","http//www.baidu.com");
response.printlin("");
}else if ("/setCookie".equals(request.getUri())){
response.setStatus(200);
response.setMessage("OK");
response.addheader("Set-Cookie","studentid= " + UUID.randomUUID());
response.printlin("<h1>Set Cookie OK</h1>");
}else if ("GET".equals(request.getMethod()) && "/login.html".equals(request.getUri())){
response.setStatus(200);
response.setMessage("OK");
BufferedReader reader = new BufferedReader(new
InputStreamReader(MyServer.class.getClassLoader().getResourceAsStream("login.html")));
String line;
while ((line = reader.readLine()) != null){
response.printlin(line);
}
}else if ("POST".equals(request.getMethod()) && "/login".equals(request.getUri())){
response.setStatus(200);
response.setMessage("OK");
response.printlin("<h2>欢迎您,用户" + request.getParameters("username") + "</h2>");
String sessionId = UUID.randomUUID().toString();
response.addheader("Set-Cookie","JSESSIONID= " + sessionId);
SESSION.put(sessionId,"用户名: " + request.getParameters("username") + ", 计算机2020届学生");
}else if ("/getSession".equals(request.getUri())){
response.setStatus(200);
response.setMessage("OK");
response.printlin("<h1>" + SESSION.get(request.getCookie("JSESSIONID")) + "</h1>");
}else {
response.setStatus(404);
response.setMessage("Not Found");
response.printlin("<h1>没有找到资源</h1>");
}
response.flush();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}catch (IOException e){
e.printStackTrace();
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>这是标题</title>
</head>
<body>
<h1>用户注册</h1>
<form method="post" action="login">
<label>姓名: </label><input name="username" type="text" />
<label>密码: </label><input name="password" type="password" />
<input type="submit" value="提交" />
</form>
</body>
</html>
记得将目录mark as resource
本文介绍了HTTP协议的基本格式,包括请求和响应的结构,重点讲解了Session和Cookie在HTTP中的作用,用于实现会话状态保持。讨论了Cookie的安全问题以及Session作为替代方案的优势,并对比了两者的区别。同时提到了Set-Cookie头部字段在设置Cookie中的应用。

824

被折叠的 条评论
为什么被折叠?



