需要先了解一下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.