基于Java实现一个自己的HTTP浏览器

 更新时间:2024年01月29日 15:15:42   作者:纵横千里,捭阖四方  
这篇文章主要为大家详细介绍了如何基于Java实现一个自己的HTTP浏览器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

在讨论HTTP协议的具体请求和响应头字段之前,让我们先来利用以前所学的知识来实现一个HTTP模拟器。所谓HTTP模拟器就是可以在用户输入HTTP的请求消息后,由这个模拟器将HTTP请求发送给相应的服务器,再接收服务器的响应消息。这个HTTP模拟器有几下特点:

1.  可以手工输入HTTP请求,并向服务器发送。

2.  接收服务器的响应消息。

3.  消息头和实体内容分段显示,也就是说,并不是象Telnet等客户端一样将HTTP响应消息全部显示,而是先显示消息头,然后由用户决定是否显示实体内容。

4.  集中发送请求。这个HTTP模拟器和Telnet不同的是,并不是一开始就连接服务器,而是将域名、端口以及HTTP请求消息都输完后,才连接服务器,并将这些请求发送给服务器。这样做的可以预防服务器提前关闭网络连接的现象。

5. 可以循环做上述的操作。

从以上的描述看,要实现这个HTTP模拟器需要以下五步:

  • 主线程里建立一个死循环的while,在循环内部是一个请求/响应对。这样就可以向服务器发送多次请求/响应以了。下面的四步都是被包括在循环内部的。
  • 从控制台读取域名和端口,这个功能可以由readHostAndPort(...)来完成。
  • 从控制台读取HTTP请求消息,这个功能由readHttpRequest(...)来完成。
  • 向服务器发送HTTP请求消息,这个功能由sendHttpRequest()来完成。
  • 读取服务器回送的HTTP响应消息,这个功能由readHttpResponse(...)来完成。

下面我们就来逐步实现这五步:

1.主线程循环体

在建立这个循环之前,先建立一个中叫HttpSimulator的类,并在这个类中定义一个run方法用来运行这个程序。实现代码如下:

public class HttpSimulator {
    private Socket socket;
    private int port = 80;
    private String host = "localhost";
    private String request = ""; // HTTP请求消息 012
    private boolean isPost, isHead;
 
    public void run() throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true)  // 开始大循环
        {
            try {
                if (!readHostAndPort(reader)) break;
                readHttpRequest(reader);
                sendHttpRequest();
                readHttpResponse(reader);
            } catch (Exception e) {
                System.out.println("err:" + e.getMessage());
            }
 
        }
    }
 
    public static void main(String[] args) throws Exception {
        new HttpSimulator().run();
 
    }

从上面的代码可以看出,我们分别调用了上述的四个方法。这些方法的具体实现将在后面讨论。上面的代码除了调用这四个核心方法外,还做了一些准备工作。在008至012行定义了一些以后要用到的变量。在016和017行使用控制台的输入流建立了BufferedReader对象,通过这个对象,可以直接从控制台读取字符串,而不是一个个地字节。

2.readHostAndPort()方法的实现

这个方法的主要功能是从控制台读取域名和端口。域名和端口通过":"隔开,":"和域名以及端口之间不能有空格。当从控制台读取一个"q"时,这个函数返回false,表示程序可以退出了,否则返回true,表示输入的域名和端口是正确的。这个方法的实现代码如下:

    private boolean readHostAndPort(BufferedReader consoleReader) throws Exception {
        System.out.print("host:port>");
        String[] ss = null;
        String s = consoleReader.readLine();
        if (s.equals("q")) return false;
        else {
            ss = s.split("[:]");
            if (!ss[0].equals("")) host = ss[0];
            if (ss.length > 1) port = Integer.parseInt(ss[1]);
            System.out.println(host + ":" + String.valueOf(port));
            return true;
        }
    }

上面的代码,我们做一个分析:

这个方法有一个BufferedReader类型的参数,这个参数的值就是在HttpSimulator.java中的第016和017行根据控制台输入流建立的BufferedReader对象。

这输出HTTP模拟器的控制符,就象Windows的控制台的"C:">"一样。

consoleReader.readLine()从控制台读取一行字符串。

ss = s.split("[:]") 通过字符串的split方法和响应的正则表示式("[:]")将域名和端口分开。域名的默认值是localhost,端口的默认值是80。 

3.readHttpRequest()方法的实现

这个方法的主要功能是从控制台读取HTTP请求消息,如果输入一个空行,表示请求消息头已经输完;如果使用的是POST方法,还要输入POST请求的实体内容。这个方法的实现代码如下:

    private void readHttpRequest(BufferedReader consoleReader) throws Exception {
        System.out.println("请输入HTTP请求:");
        String s = consoleReader.readLine();
        request = s + "\r\n";
        boolean isPost = s.substring(0, 4).equals("POST");
        boolean isHead = s.substring(0, 4).equals("HEAD");
        while (!(s = consoleReader.readLine()).equals("")) {
            request = request + s + "\r\n";
        }
        request = request + "\r\n";
        if (isPost) {
            System.out.println("请输入POST方法的内容:");
            s = consoleReader.readLine();
            request = request + s;
 
        }
    }

上面的代码,我们简单解释一下:

consoleReader.readLine() 读入HTTP请求消息的第一行。

isPost 和isHead 用于确定所输入的请求方法是不是POST和HEAD。之后的代码读入HTTP请求消息的其余行。

if (isPost) 代码段的功能是:如果HTTP请求使用的是POST方法,要求用户继续输入HTTP请求的实体内容。

4.sendHttpRequest()方法的实现

这个方法的功能是将request变量中的HTTP请求消息发送到服务器。下面是这个方法的实现代码:

   private void sendHttpRequest() throws Exception {
        socket = new Socket();
        socket.setSoTimeout(10 * 1000); //设置读取数据超时为10秒。
        System.out.println("正在连接服务器");
        socket.connect(new InetSocketAddress(host, port), 10 * 1000); //超时时间
        System.out.println("服务器连接成功!");
        OutputStream out = socket.getOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(out);
        writer.write(request);
        writer.flush();
 
    }

5.readHttpResponse(...)方法的实现

这个方法的主要功能是从服务器读取返回的响应消息。首先读取了响应消息头,然后要求用户输入Y或N以确定是否显示响应消息的实体内容。这个程序之所以这样做,主要有两个原因:

(1) 为了研究HTTP协议。

(2) 由于本程序是以字符串形式显示响应消息的,因此,如果用户请求了一个二进制Web资源,如一个rar文件,那么实体内容将会显示乱码。所以在显示完响应消息头后由用户决定是否显示实体内容。

这个方法的实现代码如下: 

 private void readHttpResponse(BufferedReader consoleReader) {
        String s = "";
        try {
            InputStream in = socket.getInputStream();
            InputStreamReader inReader = new InputStreamReader(in);
            BufferedReader socketReader = new BufferedReader(inReader);
            System.out.println("---------HTTP头---------");
 
            boolean b = true; // true: 未读取消息头 false: 已经读取消息头 011
            while ((s = socketReader.readLine()) != null) {
                if (s.equals("") && b == true && !isHead) {
                    System.out.println("------------------------");
                    b = false;
                    System.out.print("是否显示HTTP的内容(Y/N):");
                    String choice = consoleReader.readLine();
                    if (choice.equals("Y") || choice.equals("y"))   {
                        System.out.println("---------HTTP内容---------");
                        continue;
 
                    }                    else break;
 
                } else System.out.println(s);
 
            }
        } catch (Exception e) {
            System.out.println("err:" + e.getMessage());
 
        } finally {
            try {
                socket.close();
 
            } catch (Exception e) {
 
            }
        } System.out.println("------------------------");
 
    }

在上面的代码中013行是最值得注意的。其中s.equals("")表示读入一个空行(表明消息头已经结束);由于在实体内容中也可以存在空行,因此,b == true来标记消息头是否已经被读过,当读完消息头后,将b设为false,如果以后再遇到空行,就不会当成消息头来处理了。当HTTP请求使用HEAD方法时,服务器只返回响应消息头;因此,使用!isHead来保证使用HEAD发送请求时不显示响应消息的内容实体。

现在我们已经实现了这个HTTP模拟器,下面让我们来运行并测试它。 

我们将上面的代码执行起来,然后会有个输入的提示:

我们输入www.csdn.net

然后继续分行输入如下的HTTP请求消息:

GET / HTTP/1.1
Host: www.csdn.net

之后根据提示输入Y,运行的结果如下所示:

------------------------
是否显示HTTP的内容(Y/N):Y
---------HTTP内容---------
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>WAF</center>
</body>
</html>

到此我们就实现了一个简单的HTTP浏览器了。

到此这篇关于基于Java实现一个自己的HTTP浏览器的文章就介绍到这了,更多相关Java实现HTTP浏览器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java JVM原理与调优_动力节点Java学院整理

    Java JVM原理与调优_动力节点Java学院整理

    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。下面通过本文给大家介绍jvm原理与调优相关知识,感兴趣的朋友一起学习吧
    2017-04-04
  • 剑指Offer之Java算法习题精讲二叉树专项解析

    剑指Offer之Java算法习题精讲二叉树专项解析

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03
  • Java 深入理解创建型设计模式之抽象工厂模式

    Java 深入理解创建型设计模式之抽象工厂模式

    当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式,抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态
    2022-02-02
  • Java正则表达式基础语法详解

    Java正则表达式基础语法详解

    这篇文章主要介绍了Java正则表达式语法,包括常用正则表达式、匹配验证-验证Email是否正确以及字符串中查询字符或者字符串,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • 详解Java程序并发的Wait-Notify机制

    详解Java程序并发的Wait-Notify机制

    这篇文章主要介绍了详解Java程序并发的Wait-Notify机制,多线程并发是Java编程中的重要部分,需要的朋友可以参考下
    2015-07-07
  • Java中的模板模式说明与实现

    Java中的模板模式说明与实现

    这篇文章主要介绍了Java中的模板模式说明与实现,模板方法模式,又叫模板模式,在一个抽象类公开定义了执行它的方法的模板,它的子类可以更需要重写方法实现,但可以成为典型类中定义的方式进行,需要的朋友可以参考下
    2023-10-10
  • SpringBoot前后端分离实现个人博客系统

    SpringBoot前后端分离实现个人博客系统

    这篇文章主要为大家详细介绍了使用springboot+mybatis+前端vue,使用前后端分离架构实现的个人博客系统,感兴趣的小伙伴可以动手尝试一下
    2022-06-06
  • IDEA社区版下载安装流程详解(小白篇)

    IDEA社区版下载安装流程详解(小白篇)

    这篇文章主要介绍了IDEA社区版下载安装流程详解(小白篇),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 基于springboot拦截器HandlerInterceptor的注入问题

    基于springboot拦截器HandlerInterceptor的注入问题

    这篇文章主要介绍了springboot拦截器HandlerInterceptor的注入问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java中截取字符串方法的两种用法

    Java中截取字符串方法的两种用法

    这篇文章主要给大家介绍了关于Java中截取字符串方法的两种用法,在Java开发中经常会涉及到对字符串进行截取操作,字符串截取是一种常见且重要的字符串处理技巧,可以根据实际需求获取字符串的指定部分,需要的朋友可以参考下
    2023-09-09

最新评论