HTTP 代理服务器的设计与实现

HTTP 代理服务器的设计与实现

首先当然是最重要的代码:github地址

1) 实验目的

熟悉并掌握 Socket 网络编程的过程与技术;深入理解 HTTP 协议,掌握 HTTP 代理服 务器的基本工作原理;掌握 HTTP 代理服务器设计与编程实现的基本技能。

2) 实验内容

基于 java 实现了基本功能与全部附加功能,并增加了 https 的支持

(1) 设计并实现一个基本 HTTP 代理服务器。要求在指定端口(例如 8080)接收来自客户的 HTTP 请求并且根据其中的 URL 地址访问该地址所指向的 HTTP 服务器(原服务器),接收 HTTP 服务器的响应报文,并将响应报文转发给对应的客户进行浏览。
(2) 设计并实现一个支持 Cache 功能的 HTTP 代理服务器。要求能缓存原服务器响应的对象, 并能够通过修改请求报文(添加 if-modified-since 头行),向原服务器确认缓存对象是否是最 新版本。(选作内容,加分项目,可以当堂完成或课下完成)
(3) 扩展 HTTP 代理服务器,支持如下功能:(选作内容,加分项目,可以当堂完成或课下 完成)

  • 网站过滤:允许/不允许访问某些网站;
  • 用户过滤:支持/不支持某些用户访问外部网站;
  • 网站引导:将用户对某个网站的访问引导至一个模拟网站(钓鱼)。

实验过程及结果

  1. 设置代理服务器:
    在设置中启用代理服务器设置代理服务器地址为 127.0.0.1(localhost), 端口 8080
  2. Socket 编程的客户端和服务器端主要步骤;
    服务器端的建立: 服务器端比较简单,只需接受请求并开启新线程处理即
    可,使用 ServerSocket 接收请求,在循环中使用 accept 方法当收到新请求 时开启处理请求的子线程进行处理。
    客户端建立: 客户端接收新 accept 生成的新 socket,使用 scanner 解析其 内容获取其中请求头,host,port 如果没有 port 默认 80 端口,https 则为 443 端口,根据 host 和 port 构造与目的地址的新 socket,转发请求
    头,继续将目的主机返回的内容通过代理服务器转发给浏览器,并将浏览
    器的请求转发给目的主机output.write(input.read());由于两个转发是同
    时进行的,所以需要开启新的线程处理其中一个请求,另一个在主线程中
    完成。
    ReadScanner: 将浏览器发来的请求头解析成 string,并获得其中的 host, port,type(http 还是 https),并提供获取 head,host,port,type 的方法
    屏蔽特定用户: 因为内网只能屏蔽自己,调用 socket 的 getInetAddress 方 法获取访问的地址,与要屏蔽的地址对比,如果相同则直接 return
    钓鱼: 同样根据 host,判断 host 是否为要钓鱼的网站,如果是则将 host 替换为指定网站,并将 head 头替换为事先准备好的头,接下来和普通处 理一样。
    Cache: 最难的一个附加功能,通过内存存储的数据,在客户端使用 static 静态变量使所有进程共享缓存,创建 cacheMap 存储缓存,创建 lastTimeMap 存储 Last-Modigied 时间,读取到 host 时首先判断缓存和 lastTime 的 key 中 是否纯 在 host , 如 果 有 , 在 head 头 中 加 上 If-Modified-Since: 和时间注意换行,收到服务器的返回后首先截取前 1000 个字节,处理成字符串判断是否有 304 Not Modified,如果是则将之 前的缓存直接写入并 flush 并 return,还需通过前 1000 字节判断是否有 Last-Modified 时间,如果有,则将时间和缓存加入到 lastTimeMap 和 cacheMap 中,并将前 1000 字节也写回浏览器,后面的内容处理直接写回 浏览器即可。
    https: 由于 https 加密传输,首先用 type 判断是否为 https,如果是,返回 "HTTP/1.1 200 Connection Established\r\n\r\n"建立隧道,之后 flush,之后 的内容直接转发即可,但也由于加密,无法判断缓存
  3. HTTP 代理服务器的基本原理;
    客户端每次请求都要直接发送到该代理服务器,并由代理服务器根据收到
    的请求建立新的 socket 代替客户端去请求,并将收到的内容转发给客户 端。
  4. HTTP 代理服务器的程序流程图;
    HTTP 代理服务器的设计与实现
  5. 实现 HTTP 代理服务器的关键技术及解决方案;
    a) 创建 ServerSocket,通过 accept 接收请求,生成 socket 的子线程
    b) 子线程接收请求,处理请求头获取 host,port,head 等,通过 scanner 解 析,换行加入\r\n,注意当长度为 0 时退出循环,否则会卡死
    c) https 的实现:获取解析的 type,如果是 connect,返回"HTTP/1.1 200 Connection Established\r\n\r\n"建立 https 隧道之后直接转发即可
    d) 难点在于 cache:通过 map 存储缓存和最后版本的时间,缓存用 List 的 Byte 存储,通过其中是否含有 key 是否含有缓存,如果含有,转发时加 上 If-Modified-Since:并加上时间,并截取返回的前 1000 字节,使用list存储,此时先不写入,如果返回 304,将之前的缓存直接写入, 如果没有,先将之前的 1000 字节写入,之后直接转发写入即可,同时判 断其中是否含有 last-Modified,如果有,将缓存的 list 放入 map 中,后 面的 list 仍然后加入新的读入,由于存入的时 list 的地址,所以 map 里 的缓存一样会改变。并将最后版本的时间加入 lastTimeMap
    e) 其他的附加功能只需要判断 host 更改请求头 host 等即可完成