今天学习的内容是初识Web开发
目前我们已经了解客户端与服务器进行网络数据传输的底层原理(将网络层和传输层封装为Socket,使用IO流进行数据传输),这种网络结构称为C/S架构。随着互联网的兴起,基于Web浏览器与Web服务器的网络结构逐渐成为主流,这种网络结构则称为B/S架构。所谓的Web开发(属于应用层开发)就是在处理Web浏览器与Web服务器之间的交互,具体来说就是浏览器发出用户请求,服务器处理用户请求并返回响应。绝大多数的Web开发都是构建在HTTP协议之上的Web应用。HTTP协议(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,底层协议通常为TCP/IP。
在开发Web应用时,通常不用考虑底层(Web浏览器与Web服务器已经将这些内容封装好了),重点在于如何处理用户请求,并将处理结果以响应的形式返回给用户。例如用户通过在浏览器输入URL请求某HTML页面,服务器就会将这个HTML页面以响应形式返回给用户。那为什么不同浏览器发出的请求可以被不同服务器所处理,不同服务器返回的响应可以被不同浏览器所解析呢?这就体现了HTTP协议的重要性!浏览器发出的是HTTP请求,是由请求行+请求首部+请求主体组成的,服务器会根据HTTP请求中的信息处理请求;同理,服务器返回的是HTTP响应,是由状态行+响应首部+响应主体组成的(上例中的HTML页面就在响应主体里面),浏览器会根据HTTP响应中的信息解析响应。
上述内容将会在后面详细学习。不过我们可以通过现有知识模拟Web浏览器和Web服务器的工作原理,首先模拟Web服务器:
public class MyWebServer {
@SuppressWarnings("resource")
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(9090);
while (true) {
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String httpRequest = new String(buf, 0, len);
System.out.println(httpRequest);// 将浏览器发送过来的HTTP请求打印到控制台
PrintWriter out = new PrintWriter(socket.getOutputStream());
//模拟HTTP响应
out.println("HTTP/1.1 200 OK");// 状态行
out.println("Server: Apache-Coyote/1.1");
out.println("Accept-Ranges: bytes");
out.println("Content-Type: text/html");
out.println("Date: Wed, 07 Dec 2016 03:37:35 GMT");
out.println("");//响应主体与响应首部之间的空行
out.println("<html>");
out.println("<head></head>");
out.println("<body>");
out.println("欢迎光临");
out.println("</body>");
out.println("</html>");
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
启动模拟服务器进程并在浏览器地址栏输入URL:http://localhost:9090/ 控制台和浏览器显式结果:
浏览器将HTTP请求发给了模拟服务器进程,浏览器接收到模拟服务器返回的模拟HTTP响应并进行了解析。
下面再来模拟Web浏览器:
public class MyBrowser {
public static void main(String[] args){
Socket socket = null;
try {
socket = new Socket(InetAddress.getLocalHost(),8080);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println("GET /test/test.html HTTP/1.1");
out.println("Host: www.localhost:9090");
out.println("Accept:*/*");
out.println("Connection: keep-alive");
out.println("");//请求首部与请求主体之间的空行
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String httpResponse = null;
while((httpResponse = in.readLine())!=null){
System.out.println(httpResponse);
}
System.out.println("结束");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
socket.close();
} catch (IOException e) {
System.out.println("关闭资源失败");
}
}
}
}
开启Tomcat服务,并启动模拟浏览器进程,控制台显示结果:
模拟浏览器进程将模拟HTTP请求发给了Tomcat服务器,模拟浏览器接收到Tomcat返回的HTTP响应并打印到控制台。
当然,实际上Web开发远远没有这么简单!不仅服务器处理HTTP请求的过程更加复杂(数据库、会话、MVC等等),而且通常会涉及到动态页面的开发(JSP),还需要学习很多知识!