java网络编程:基于HTTP的下载程序设计及web浏览器制作(完整代码实现)

第8讲 HTTP程序设计

教学与实践目的:学会WEB浏览器基本的程序设计技术。

一、概述

HTTP系统包括客户端软件(浏览器)和服务器软件(HTTP服务器)。早期的客户端软件,其主要工作可理解为文件下载和文件显示。

实际上现代的HTTP客户端比文件下载要复杂得多,它包括网页文件的下载、跨平台的本地显示,参数的传递,动态网页的实现,以及交互等功能。

HTTP系统程序设计包括:

(1)客户端软件(web浏览器软件如edge浏览器、360浏览器);

(2)服务器软件(web服务器软件如微软的IIS,Apache Tomcat等)。

HTTP系统客户端的工作过程是:

(1)客户端软件和服务器建立连接(TCP的三次握手);

(2)发送HTTP头格式协议;

(3)接收网页文件;

(4)显示网页。

HTTP系统服务端的工作过程:

(1)服务器软件开启80端口;

(2)响应客户的要求、完成TCP连接;

(3)检查客户端的HTTP头格式发送客户请求的网页文件(含动态网页)。

一个完整的HTTP请求-响应如图8.1所示:

图8.1 HTTP请求-响应

本讲主要学习网页下载程序设计技术。网页下载技术是搜索引擎、网络爬虫、网页采集器或网络推送服务等相关应用领域内的基础技术。

二、程序设计第一步:基于TCP套接字的网页下载程序设计

利用TCP客户套接字Socket和HTTP服务器进行信息交互,将网页的原始内容下载显示在图形界面中,具体工作如下:

(1)新建一个包chapter08,将第3讲的TCPClient.java复制到此包下,重命名为HTTPClient.java;

(2)创建HTTPClientFX.java程序,界面如图8.2所示,网页地址输入www.baidu.com进行测试,端口为80,在“连接”按钮类似以往的编码方式,放置连接服务器的代码和启动输入流“读线程”。在“网页请求”按钮中发送HTTP请求头标准格式(关于HTTP请求头的更多信息可查阅互联网)。

image-20201108113600570

图8.2 手动发送HTTP请求的HTTP连接窗口

我们的程序可以按顺序发送以下HTTP请求头:

GET / HTTP/1.1 //访问默认网页,注意‘/’前后要留有空格

HOST: address  //address指服务器的IP或域名

Accept: 

Accept-Language: zh-cn

User-Agent: User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) 

Connection: Keep-Alive

将上述的HTTP头格式构成一个字符串(通常用StringBuffer类,其toString()方法可将内容转换为字符串),一致发送到HTTP服务器。

​ 如果网页信息显示区返回的第一条信息是“HTTP/1.1 200 OK”,则说明访问正常。

现在将网页地址改为www.gdufs.edu.cn,其它不变,再次连接并点击网页请求,结果如图8.3所示:

image-20201108113606554

图8.3 HTTP/1.1 302 Found

这种情况HTTP服务器确实有内容返回,却不是我们预期的内容,第一行内容为“HTTP/1.1 302 Found”,这种情况一般是站点关闭了HTTP,只允许启用了SSL/TLS的HTTPS安全连接,这种连接默认是使用443端口。事实上,出于安全考虑,现在绝大部分的web站点都将放弃HTTP而启用HTTPS。

三、程序设计第二步:基于SSL Socket的网页下载程序设计

要访问HTTPS站点,就不能用普通的客户端套接字,而是使用SSL套接字。Java安全套接字扩展(Java Secure Socket Extension,JSSE)为基于SSL和TLS协议的Java网络应用程序提供了Java API以及参考实现,相关的类都定义在javax.net.ssl包下面,我们这里只使用其客户端的SSLSocket套接字。SSLSocket相对之前学习的客户端套接字,只是创建方法不同,SSLSocket对象由SSLSocketFactory创建,创建之后用法几乎一致。具体工作如下:

(1)根据HTTPClient.java的内容,稍作修改,新创建HTTPSClient.java程序,与前者相比,主要区别的代码如下:

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;
public class HTTPSClient {
   
 //定义SSL套接字
 private SSLSocket socket;
 //定义SSL工厂类
 private SSLSocketFactory factory;
 //定义字符输入流和输出流
  ……
 
 public HTTPSClient(String ip, String port) 
   throws IOException {
   
  factory =(SSLSocketFactory)SSLSocketFactory.getDefault();
  //创建安全套接字实例
  socket = (SSLSocket)factory.createSocket(ip,
    Integer.parseInt(port));

……

……

……
 }

……

……
}


(2)根据HTTPClientFX.java程序的内容,稍做修改,新创建一个HTTPSClientFX.java程序(实质上只需要将原来的使用HTTPClient及其对象实例的的地方修改为使用HTTPSClient及其对象实例即可)。

(3)运行该程序,界面如图8.4所示,可以看到已经能够正常获取到广外官网首页的内容。

image-20201108113629946

图8.4 TCP SSL套接字访问下载网页内容

(4)完全没有必要使用两个不同的图形界面来分别访问http和https,创建一个HTTPAllClientFX.java,融合以上两个图形客户端的功能,使得该图形客户端即可访问443的https内容,也可以访问非443端口(一般是80)的http内容。

四、程序设计第三步:基于URL类的网页下载程序设计

前面直接发送http请求的程序,对于复杂的地址,例如指向具体页面的地址,无法完成网页下载任务,我们可以使用基于URL类的解决方案。

URL(Uniform Resource Locator)中文名为统一资源定位符,用于表示资源地址,资源如网页或者FTP地址等。

URL的格式为protocol://资源地址,protocol可以是HTTP、HTTPS、FTP 和 File,资源地址中可以带有端口号及查询参数,具体可以自行搜索URL的知识。

在java.net包中定义了URL类,该类用来处理有关URL的内容。并且其封装有一个InputStream返回类型的openStream()方法,我们的程序就可以读取这个字节输入流来获得对应内容。

(1)创建程序URLClientFX.java,界面布局可参见如图8.5所示:

image-20201108113634992

图8.5 使用URL类

发送按钮事件响应中的关键代码:

taDisplay.clear();
String address = tfSend.getText().trim();
try {
   
 URL url = new URL(address);
 System.out.printf("连接%s成功!\n", address);

 //获得url的字节流输入
 InputStream in = url.openStream();
 //装饰成字符输入流
 br = new BufferedReader(new InputStreamReader(in, "utf-8"));

 //用于接收信息的单独线程

…….


请注意URL方式和直接发送HTTP请求报头的方式,返回结果有何不同。

(2)如果用户的输入不符合URL语法,你的程序不是简单地报错,而是在显示区提醒用户输入地址不合规,如图8.6所示。

image-20201108113640439

图8.6 不合规URL示意图

五、扩展练习:web浏览器

上述程序设计仅仅实现了网页文件的下载,若想要一定的网页显示功能,可以使用JavaFX的WebEngine和WebView组件。

(1)WebEngine类

WebEngine类提供了基本的web页面功能。尽管它并不与用户直接交互,但它也支持用户交互,如导航链接和提交HTML表单。WebEngine类一次处理一个web页面。它支持加载HTML内容和访问DOM对象等基本功能,也支持执行JavaScript指令。

有两个构造方法能够创建WebEngine对象:空构造和带一个URL参数的构造。如果你使用空构造方法来实例化它,那么URL可以通过WebEngine对象的load()方法来传入。WebEngine对象实例的getLocation()方法会返回当前加载页面的URL地址。

(2)WebView类

WebView类是Node类的一个扩展。它封装了WebEngine对象,将HTML内容加入程序的scene中,并且提供各种属性和方法来应用特效和变换。WebView对象的getEngine()方法返回一个与之关联的web engine,例如可以这样使用:

WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();

webEngine.load(“https://www.gdufs.edu.cn”);

广外首页的内容就会加载显示在webView组件中,webEngine 如果再次 load另外一个URL,则webView就自动加载另外一个页面的内容。

(3)WebHistory类

WebHistory类可获取已访问的页面列表,它表示与WebEngine对象关联的一个会话历史记录。使用WebEngine.getHistory()方法来获取某特定webEngine对象的WebHistory实例, 即:WebHistory history = webEngine.getHistory();

该历史记录基本上是一种特殊类型的列表。类似普通List,该列表也是下标从0开始,每一个条目表示一个已访问过的页面并且提供对该页面相关信息的访问。该列表可通过getEntries()方法获得。该对象的getCurrentIndex()方法返回值表示当前访问页面在列表中的索引位置。该对象的go(int index)方法表示页面的跳转,例如history.go(-1)就是返回上一个访问的页面,history.go(1)表示前进到下一个访问过的页面,这两个方法使用要注意边界条件判断,否则会抛出异常,例如已经没有可回退的页面记录,再执行回退方法就抛出异常。

(4)创建一个javaFX程序,命名为WebBrowserFX.java,参考界面如图8.8所示,完成界面所示的功能。

image-20201108113704982

图8.8 WebBrowserFX参考界面

(5)实现附加功能:

要求“前进”和“后退”按钮能够根据实际情况自动禁用和启用;

在地址框中输入URL地址,回车后载入页面,但如果点击链接后,页面跳转,地址框的地址默认是不会跟随变化的。实现该功能:能自动更新为当前页面的URL地址。

提示:使用webEngine的状态监听器,监听页面的载入状态,只要页面有载入动作,就会触发其中的代码。在这个监听器中,我们就可以将访问的URL地址及时更新到地址栏,并设置前进后退按钮的可用性:

webEngine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {

//……… 省略,自行实现

});

完整代码实现

HTTPAllClientFX

package chapter08;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;

/**
 * Author:
 * Data:2020/10/24
 * description:
 */
public class HTTPAllClientFX extends Application {
   
    private Button btnConnect = new Button("连接");
    private Button btnClose = new Button("退出");
    private Button btnClear = new Button("清空");
    private Button btnHttp = new Button("网页请求");
    private TextField tfUrl = new TextField("www.gdufs.edu.cn");
    private TextField tfPort = new TextField("443");
    private TextArea taDisplay = new TextArea();
    private HTTPClient httpClient;
    private HTTPSClient httpsClient;
    Thread readThread;
    String url;
    String port;
    @Override
    public void start(Stage primaryStage){
   
        BorderPane mainpane = new BorderPane();
        HBox tophbox = new HBox();
        tophbox.setSpacing(10);
        tophbox.setPadding(new Insets(10,20,10,20));
        tophbox.setAlignment(Pos.CENTER);
        tophbox.getChildren().addAll(new Label("网页地址"),tfUrl,new Label("端口"),tfPort,btnConnect);

        VBox vBox = new VBox();
        vBox.setPadding(new Insets(10,20,10,20));
        vBox.setSpacing(10);
        vBox.getChildren().addAll(new Label("信息显示区"),taDisplay);
        HBox buttomHbox = new HBox();
        buttomHbox.setPadding(new Insets(10,20,10,20));
        buttomHbox.setSpacing(10);
        buttomHbox.setAlignment(Pos.CENTER_RIGHT);
        buttomHbox.getChildren().addAll(btnHttp,btnClear,btnClose);
        mainpane.setTop(tophbox);
        mainpane.setCenter(vBox);
        mainpane.setBottom(buttomHbox);
        Scene scene = new Scene(mainpane,800,400);
        primaryStage.setScene(scene);
        primaryStage.show();

        btnConnect.setOnAction(event -> {
   
             url = tfUrl.getText().trim();
             port = tfPort.getText().trim();
             if(port.equals("443")) {
   
                 try {
   
                     httpsClient = new HTTPSClient(url, port);
                     taDisplay.appendText("服务器启动");
                     // 多线程不需要这一条了
//                String firstMsg = tcpClient.receive();
//                taDisplay.appendText(firstMsg+"\n");
//                btnConnect.setDisable(true);
                     //多线程方法

                     readThread = new Thread(() -> {
   
                         String msg = null;
                         while ((msg = httpsClient.receive()) != null) {
   
                             String msgTemp = msg;
                             Platform.runLater(() -> {
   
                                 taDisplay.appendText(msgTemp + "\n");
                             });
                         }
                         Platform.
  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Web的文件服务器是一个网络应用程序,它允许用户在Web浏览器中上传、下载、查看和管理文件。以下是基于Web的文件服务器的设计实现的一些关键点: 1. 服务器端:服务器端可以使用任何编程语言和框架来实现,例如Java、Python、Node.js等。服务器需要能够处理HTTP请求和响应,以及文件上传和下载。 2. 数据库:文件服务器需要一个数据库来存储文件的元数据,例如文件名、大小、上传时间等。数据库可以使用关系型数据库或NoSQL数据库。 3. 用户认证:为了保护文件的安全性,文件服务器需要用户认证机制。用户可以使用用户名和密码登录,服务器可以使用会话机制来维护用户的身份认证状态。 4. 文件上传和下载:文件服务器需要实现文件上传和下载功能。上传文件时,服务器需要验证用户的身份认证,检查文件大小和类型,然后将文件存储在服务器上。下载文件时,服务器需要检查用户的身份认证,然后将文件发送给用户的浏览器。 5. 文件管理:文件服务器需要提供文件管理功能,例如创建、删除、移动和重命名文件。这可以通过在Web界面中提供文件浏览器实现。 6. 安全性:文件服务器需要考虑安全性问题,例如防止未经授权的访问、跨站点脚本攻击和文件上传漏洞。服务器可以通过使用HTTPS、输入验证和输出过滤等技术来提高安全性。 7. 性能和可伸缩性:文件服务器需要考虑性能和可伸缩性问题。服务器可以使用缓存、负载均衡和分布式文件系统等技术来提高性能和可伸缩性。 总的来说,基于Web的文件服务器的设计实现是一个复杂的任务,需要考虑多个方面的问题。但是,通过使用现代的编程语言和框架,可以实现高效、安全和可靠的文件服务器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值