计算机网络应用层(超详细!)
应用层功能
在应用进程间传输报文,实现特定类型的数据交互,去执行特定的功能。
HTTP 协议
(超文本传输协议)负责发布和接收 HTML 页面和其他 Web 资源,即 Web 通信。底层通信通过 TCP 协议实现,默认端口号 80 。
资源定位
HTTP 协议通过 URL 来访问资源。URL 即 WEB 内容访问标识符,是一种具体的 URI。不仅唯一标识资源,而且还提供了定位该资源的信息。
通用格式为:协议://IP地址或域名:端口号/文件路径?参数
,如 http://localhost:443/student?id=10&name=mrjoker
连接方式
- HTTP/1.0
默认使用短连接:访问页面时,客户端和服务器之间每次 HTTP 操作都会单独使用一次 TCP 连接,传输完毕后自动关闭。
客户端和服务器之间都会建立多个 HTTP 会话,开销较大。
- HTTP/1.1
默认使用长连接:访问页面时,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,直到 HTML 页面调用的所有 web 资源传输完毕。
长连接会在 HTTP 响应头标注:Connection:keep-alive
但 HTTP/1.1 是串行化处理所有 web 资源请求。一旦有请求无法正常加载,后续请求就会被阻塞。
- HTTP/2
增加了多路复用功能:让所有数据流共用同一个连接。接收到客户端 HTTP 请求后,服务器会一次性把所需要的 web 资源打包发送。
- 即使有请求无法正常加载,也不会影响处理其它 web 资源请求。
- TCP 连接在刚开始发送数据时会限制连接的最大速度,集中发送能更有效地利用 TCP 连接。
请求类型
HTTP 请求有以下四种常用类型:
-
GET:请求服务器数据,请求参数直接附在 URL 上(不够安全,仅适用于简单公开数据的请求和提交)
-
POST:向服务器提交数据,数据以表单形式提交(内容长度无上限,且不会被浏览器记录)
-
PUT:修改服务器数据(慎用)
-
DELETE:删除服务器数据(慎用)
除此之外 HTTP 协议在正式通信前还可能发出 OPTION 请求:先询问服务器当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。
主机识别
HTTP 协议是无状态协议,本身不保存请求和响应之间的通信状态。
也就是说通信过后服务器将无法相互识别客户端,因此我们必须引入其他方式让服务器记录客户端的信息。
Session & Cookie
负责记录对方主机信息,在 HTTP 通信中相互识别。cookie 保存在客户端,session 保存在服务器端。
-
客户端初次访问服务器时,服务端会自动创建 session 用来标识用户。然后在响应头 Set-Cookie 项向客户端返回 session ID。
-
客户端再次访问服务器时,会在请求头 Cookie 项向服务器发送 session ID,服务器根据 ID 查询 Session 就可以识别用户。
用户和通信的详细信息通常记录在 session 中,cookie 中只保存 session ID ,以避免信息泄露。如果客户端 cookie 被禁用,就需要利用 URL 重写把 session ID 直接附加在 URL 路径上。
Token
token 和 session ID 功能相同,都用来在 HTTP 通信中识别用户,过期刷新:
- session ID 由服务器随机生成,保存在服务器 session 中。再次访问时只需要直接比对,就可以确认客户端身份。
- token 由服务器根据用户 ID 和时间戳经过特定算法生成,服务器不保存。再次访问时服务器需要重新计算并比对,才可以确认客户端身份。
cookie 本身不安全,浏览器中 token 除放在 cookie 外,还可以放到 localStorage 中存储。浏览器发送请求时会自动携带 session ID,但发送 token 需要手动在代码中设置。由于浏览器加载 image 标签中的地址也会发送 session ID,因此使用 token 可以有效防止 CSRF 攻击。
localStorage和sessionStorage的区别; localStorage生命周期是永久,除非用户手动清除,否则这些信息将永远存在。 sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,数据也就被清空了。
HTTPS 协议
由于 HTTP 协议使用明文在互联网传送数据,易被不法分子监听和截获。我们又引入了 HTTPS 协议取而代之,默认端口 443。
HTTPS 协议在应用层下方增加了 SSL 层,使用 TLS 协议来加密和解密数据包,这样在互联网上传送的数据将经过加密。
加密方式
-
建立连接后的数据交互采用对称加密:加密密钥和解密密钥相同。
-
建立连接时协商密钥采用非对称加密:加密密钥和解密密钥不同,两个密钥互相能解密对方的加密内容。
服务器会公开一个非对称加密密钥(公钥),并保留一个非对称加密码密钥(私钥)。
证书认证
服务器公钥由数字认证机构 CA 统一认证。CA 会用自己的私钥加密服务器公钥和相应信息,生成数字证书。在客户端向 CA 查询时将证书发送给客户端核对。
CA 根证书(包含公钥)存储在用户的浏览器中,访问网址时会自动比对服务器公钥。
- 客户端向服务器发送信息:请求连接,说明自己支持的加密算法,并给出随机数 A。
- 服务器向客户端发送信息:同意连接请求,确认合适的加密算法,并给出数字证书和随机数 B。
- 客户端向 CA 核对数字证书,确认有效后得到服务器公钥。
建立连接
- 客户端向服务器发送公钥加密信息:给出随机数 C。
- 服务器通过私钥解密信息,对信息 Hash 得到数字签名;然后向客户端发送私钥加密信息:返回数字签名。
- 客户端通过公钥解密信息,核对数字签名,确认服务器收到随机数 C。
之后双方就可以按照约定的对称加密方法,使用三个随机数生成的密钥进行数据交互。
HTTP 通信
Java 程序执行 HTTP 通信的类定义在 java.net 包内,使用时需进行导入。
基本通信方式:创建连接对象 》设置连接参数和请求属性 》建立连接并发送请求 》读取响应内容 》关闭连接
创建连接对象
-
URL 类:标记定向资源所在位置,如果格式错误则抛出
IOException
。 -
URLConnection 类:读取和写入 URL 类定向的资源,在 HTTP 协议中常用 HttpURLConnection 子类。
URL myUrl = new URL("https://www.baidu.com");
HttpURLConnection myCon = (HttpURLConnection)myUrl.openConnetcion();Copy to clipboardErrorCopied
配置连接
设置请求参数
myCon.setRequestMethod("POST"); // 设置连接方法(默认使用GET)
myCon.setDoInput(true); // 允许进行字符流输入: myCon.getInputStream().read();
myCon.setDoOutput(true); // 允许进行字符流输出: myCon.getOutputStream().write();
myCon.setRequestMethod(1000); // 设置最长建立连接时间,若超时则抛出 SocketTimeoutException
myCon.setRequestMethod(1000); // 设置最长数据读取时间,若超时则抛出 SocketTimeoutExceptionCopy to clipboardErrorCopied
设置请求属性
// 设置版本
myCon.setRequestProperty("version", "1.2.3");
// 设置浏览器类型(常用于爬虫伪装)
myCon.setRequestProperty("user-agent", "Mozilla/5.0 (compatible; Windows NT 5.1;SV1)");
// 设置发送文本类型
myCon.setRequestProperty("Content-Type", "application/json;charset=utf-8");Copy to clipboardErrorCopied
连接并发送请求
- connect 方法:建立连接并发送请求.
- getOutputStream 方法:关闭输出流时自动建立连接并发送输出流请求.
myCon.connect();
OutputStreamWriter out = new OutputStreamWriter(myCon.getOutputStream());
out.write(str);
out.close();Copy to clipboardErrorCopied
获取响应数据
获取响应头信息
myCon.getResponseCode(); // 获取响应码(200为连接成功,404为未找到)
myCon.getHeaderField(); // 获取响应头字段
Copy to clipboardErrorCopied
获取响应内容
- getContent 方法:获取响应内容。
- getInputStream 方法:输入流获取响应内容,响应表明发送了错误则抛出
IOException
。
myCon.getContent();
BufferedReader in = new BufferedReader(new InputStreamReader(myCon.getInputStream()));
while ((str = in.readLine()) != null) {
System.out.println(str);
}
in.close();Copy to clipboardErrorCopied
关闭连接
myCon.disconnect();Copy to clipboardErrorCopied
HTTP 通信用例
// 网络爬虫
public class WebCrawler{
public static void getHttpJson(int i) {
try {
//配置URL
URL myUrl = new URL("https://static-data.eol.cn/www/school/"+ i + "/info.json");
//配置连接
HttpURLConnection myCon = (HttpURLConnection) myUrl.openConnection();
myCon.setRequestProperty("user-agent", "Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
myCon.setConnectTimeout(10000);
myCon.setReadTimeout(1000);
//建立连接
myCon.connect();
//如果连接成功
if (myCon.getResponseCode() == 200) {
System.out.print("ID" + i + "的数据读取成功,数据内容:");
//读取返回数据
InputStream in = myCon.getInputStream();
int cnt = in.available();
byte[] b = new byte[cnt];
in.read(b);
String str = new String(b);
//输出返回数据
System.out.println(str);
}else{
System.out.println("ID" + i + "的数据读取失败,代码:" + myCon.getResponseCode());
}
} catch (MalformedURLException e) {
System.out.println("URL错误,无法查找到资源。");
} catch(SocketTimeoutException e){
System.out.println("ID" + i + "的数据访问连接超时。");
} catch (IOException e) {
System.out.println("发送的请求存在错误,资源拒绝访问。");
}
return;
}
}
- 点赞
- 收藏
- 关注作者
评论(0)