HTTP 与 Java Web
技术公众号:Java In Mind(Java_In_Mind),欢迎关注!
HTTP协议
HTTP(HyperText Transfer Protocol,超文本传输协议),是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网数据通信的基础。
HTTP始于1989年,于1999年的HTTP/1.1版本流行至今(2015年HTTP/2,2018年HTTP/3),已经成为互联网不可或缺的协议,HTTP协议属于应用层,底层基于提供可靠传输的网络协议(基本基于TCP/IP协议,但HTTP协议没有规定使用具体协议),实现客户端与服务端的通信(请求/响应)。
HTTP客户端发起连接默认使用80端口,可以自定义端口,服务器则监听客户端请求,进行对应处理后放回响应结果(状态码,响应内容等信息)
HTTP/1.1中定义了8方法
GET
一般使用GET发出查询/读取请求,不应该产生副作用(即,幂等性),通过请求路径和请求参数或来指定要查询的资源,一般没有请求体,某些服务器,浏览器可能会对GET请求做缓存,所以不要将GET用于操作数据
HEAD
与GET类似,只不过服务区不回传资源信息,获取报头信息(元数据)
POST
向服务器提交数据,请求服务器进行数据处理(如,表单提交、文件上传等),数据包含在请求体中提交到服务器,一般用于创建资源或者修改资源。
PUT
与POST类似,一般用于更新资源,PUT操作不同于POST的是它是幂等性的,意味着多次请求结果会是一样的
DELETE
请求服务器删除指定资源
TRACE
回显服务器收到的请求,主要用于测试或诊断
OPTIONS
用于服务器告诉客户端请求的资源的所有支持的HTTP请求方法,也可以对整站(通过将 URL 设置为“*”)使用该方法。
CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式(tunnel)的代理服务器,通常用于SSL加密服务器的连接(HTTPS)
其他
HTTP支持自定义拓展方法,例如,PATCH用于修改局部资源,非幂等性
状态码
1XX
请求已经被服务器接收,例如,使用websocket,会通过101来进行协议切换
2XX
成功,请求成功被服务器接收,理解,并处理,如,200请求成功
3XX
重定向,需要后续操作才能完成这次请求,如,301会根据Location头进行重定向
4XX
请求错误,请求不被服务端理解,无法处理,一般为客户端发出的请求格式问题,如,401没有认证
5XX
服务端错误,服务端在处理该请求的时候出现错误,如,500服务内部错误
理解HTTP协议
HTTP报文
格式:
起始行(请求行/响应行)
头部
空行(CRLF)
实体
一个简单的HTTP请求报文:
GET /demo HTTP/1.1
Host: localhost
一个简单的HTTP响应报文:
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Content-Length: 10
Date: Thu, 31 Oct 2019 11:44:49 GMT
HelloWorld
-
请求格式
image
-
响应格式
image
使用Java实现一个简单HttpClient
- Server
@RestController
@RequestMapping("/demo")
@SpringBootApplication
public class DemoApplication{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping
public String helloWorld() {
return "<h3>HelloWorld</h3>";
}
}
- Client
public class SimpleClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("localhost", 8080);
OutputStream out = socket.getOutputStream();
String http = "GET /demo HTTP/1.1\r\n" +
"Host: localhost:8080\r\n" +
"\r\n";
out.write(http.getBytes(StandardCharsets.UTF_8));
out.flush();
InputStream in = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in,StandardCharsets.UTF_8));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
in.close();
socket.close();
}
}
思考
如果我们把Server端也用ServerSocket来实现,那么解析客户端不同的HTTP报文做出不同的响应不就实现了一个简单的Servlet容器的效果么?把HTTP的报文封装成request和response,把处理程序封装成Servlet,根据URL做路由,这就是Java Web的实现逻辑,而通过ServerSocket实现的程序就类似Tomcat容器,只是真实的Servlet容器要考虑许多东西,如:高并发、性能方面的问题。
- 实现一个简单的HttpServer
public class SimpleHttpServer {
private static boolean shutdown = false;
public static void main(String[] args) throws Exception {
SimpleHttpServer server = new SimpleHttpServer();
server.await();
}
public void await() throws Exception {
ServerSocket serverSocket = new ServerSocket(8888, 10, InetAddress.getByName("localhost"));
while(!shutdown){
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = reader.readLine();
while (line != null){
if("".equalsIgnoreCase(line)){
builder.append(line);
break;
}
builder.append(line).append("\r\n");
line = reader.readLine();
}
System.out.println(builder.toString());
PrintWriter out = new PrintWriter(socket.getOutputStream());
// Version & status code
out.print("HTTP/1.1 200 \r\n");
// The type of data
out.print("Content-Type: text/html\r\n");
// Will close stream
out.print("Connection: close\r\n");
// End of headers
out.print("\r\n");
out.println("<p>helloworld</p>");
out.close();
in.close();
socket.close();
}
serverSocket.close();
}
}
以上例子就可以实现从浏览器访问,然后返回一个简单的helloword页面,如果进一步把请求报文封装成request,把处理程序封装成servlet,把响应报文封装成response,那么就实现一个比较简易的HttpServer,然后把连接通过Connector管理起来,把servlet通过容器管理起来,这就是一个简单Servlet容器。