34、多系统搜索引擎前端与HTTP隧道技术应用

多系统搜索引擎前端与HTTP隧道技术应用

多系统搜索引擎前端与HTTP隧道技术应用

在Web开发中,如何高效地实现客户端与服务器之间的数据交互是一个重要的问题。本文将介绍多系统搜索引擎前端的实现,以及利用HTTP隧道技术直接处理GET数据和结果的方法,同时给出具体的代码示例和操作步骤。

多系统搜索引擎前端

在处理多系统搜索引擎前端时,需要对每个条目的值进行编码,但不包括每个条目名称与其值之间的等号(=)以及每个名称/值对之间的与符号(&)。不能简单地调用 URLEncoder.encode(someData) ,而是需要有选择地对每个名称/值对的值部分进行编码。示例如下:

String someData =
name1 + "=" + URLEncoder.encode(val1) + "&" +
name2 + "=" + URLEncoder.encode(val2) + "&" +
...
nameN + "=" + URLEncoder.encode(valN);
try {
    URL programURL = new URL(baseURL + "?" + someData);
    getAppletContext().showDocument(programURL);
} catch(MalformedURLException mue) { ... }

下面是一个完整的多系统搜索引擎前端的示例,使用 SearchApplet 小程序来实现:

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import coreservlets.SearchSpec;

/** An applet that reads a value from a TextField,
 *  then uses it to build three distinct URLs with embedded
 *  GET data: one each for Google, Infoseek, and Lycos.
 *  The browser is directed to retrieve each of these
 *  URLs, displaying them in side-by-side frame cells.
 *  Note that standard HTML forms cannot automatically
 *  perform multiple submissions in this manner.
 */
public class SearchApplet extends Applet
                          implements ActionListener {
    private TextField queryField;
    private Button submitButton;

    public void init() {
        setFont(new Font("Serif", Font.BOLD, 18));
        add(new Label("Search String:"));
        queryField = new TextField(40);
        queryField.addActionListener(this);
        add(queryField);
        submitButton = new Button("Send to Search Engines");
        submitButton.addActionListener(this);
        add(submitButton);
    }

    /** Submit data when button is pressed <B>or</B>
     *  user presses Return in the TextField.
     */
    public void actionPerformed(ActionEvent event) {
        String query = URLEncoder.encode(queryField.getText());
        SearchSpec[] commonSpecs = SearchSpec.getCommonSpecs();
        // Omitting HotBot (last entry), as they use JavaScript to
        // pop result to top-level frame. Thus the length-1 below.
        for(int i=0; i<commonSpecs.length-1; i++) {
            try {
                SearchSpec spec = commonSpecs[i];
                // The SearchSpec class builds URLs of the
                // form needed by some common search engines.
                URL searchURL = new URL(spec.makeURL(query, "10"));
                String frameName = "results" + i;
                getAppletContext().showDocument(searchURL, frameName);
            } catch(MalformedURLException mue) {}
        }
    }
}

该小程序创建一个文本框来收集用户输入,当用户提交数据时,对文本框的值进行URL编码,并生成三个不同的URL,分别用于Google、Infoseek和Lycos搜索引擎。然后使用 showDocument 方法指示浏览器在三个不同的框架单元格中显示这些URL的结果。

同时,还需要相应的HTML文件来支持该小程序,如 ParallelSearches.html SearchAppletFrame.html

<!-- ParallelSearches.html -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
<HEAD>
    <TITLE>Parallel Search Engine Results</TITLE>
</HEAD>
<FRAMESET ROWS="120,*">
    <FRAME SRC="SearchAppletFrame.html" SCROLLING="NO">
    <FRAMESET COLS="*,*,*">
        <FRAME SRC="GoogleResultsFrame.html" NAME="results0">
        <FRAME SRC="InfoseekResultsFrame.html" NAME="results1">
        <FRAME SRC="LycosResultsFrame.html" NAME="results2">
    </FRAMESET>
</FRAMESET>
<!-- SearchAppletFrame.html -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
    <TITLE>Search Applet Frame</TITLE>
</HEAD>
<BODY BGCOLOR="WHITE">
<CENTER>
<APPLET CODE="SearchApplet.class" WIDTH=600 HEIGHT=100>
    <B>This example requires a Java-enabled browser.</B>
</APPLET>
</CENTER>
</BODY>
</HTML>
HTTP隧道技术

在开发客户端和服务器端时,有时不需要总是返回整个HTML文档,而是直接将数据返回给正在运行的小程序,这种方法被称为HTTP隧道技术。它有两种主要的变体:

读取二进制或ASCII数据

使用 BufferedInputStream 或其他低级流从任意服务器端程序读取二进制或ASCII数据。客户端实现此方法需要以下七个主要步骤,且许多流操作会抛出 IOException ,因此需要将以下语句包含在 try/catch 块中:
1. 创建一个指向小程序主主机的 URL 对象:

URL currentPage = getCodeBase();
String protocol = currentPage.getProtocol();
String host = currentPage.getHost();
int port = currentPage.getPort();
String urlSuffix = "/servlet/SomeServlet";
URL dataURL = new URL(protocol, host, port, urlSuffix);
  1. 创建一个 URLConnection 对象:
URLConnection connection = dataURL.openConnection();
  1. 指示浏览器不要缓存URL数据:
connection.setUseCaches(false); 
  1. 设置任何所需的HTTP头:
connection.setRequestProperty("header", "value");
  1. 创建一个输入流:
BufferedReader in =
new BufferedReader(new InputStreamReader(
connection.getInputStream()));
  1. 读取文档的每一行:
String line;
while ((line = in.readLine()) != null) {
    doSomethingWith(line);
}
  1. 关闭输入流:
in.close();
读取序列化数据结构

当小程序与Java编写的Servlet通信时,可以使用 ObjectInputStream 直接读取高级数据结构。

客户端步骤
1. 创建一个指向小程序主主机的 URL 对象:

URL currentPage = getCodeBase();
String protocol = currentPage.getProtocol();
String host = currentPage.getHost();
int port = currentPage.getPort();
String urlSuffix = "/servlet/SomeServlet";
URL dataURL = new URL(protocol, host, port, urlSuffix);
  1. 创建一个 URLConnection 对象:
URLConnection connection = dataURL.openConnection();
  1. 指示浏览器不要缓存URL数据:
connection.setUseCaches(false); 
  1. 设置任何所需的HTTP头:
connection.setRequestProperty("header", "value");
  1. 创建一个 ObjectInputStream
ObjectInputStream in =
new ObjectInputStream(connection.getInputStream());
  1. 使用 readObject 读取数据结构:
SomeClass value = (SomeClass)in.readObject();
doSomethingWith(value);
  1. 关闭输入流:
in.close();

服务器端步骤
1. 指定正在发送二进制内容,将响应的MIME类型指定为 application/x-java-serialized-object

String contentType =
"application/x-java-serialized-object";
response.setContentType(contentType);
  1. 创建一个 ObjectOutputStream
ObjectOutputStream out = 
new ObjectOutputStream(response.getOutputStream());
  1. 使用 writeObject 写入数据结构:
SomeClass value = new SomeClass(...);
out.writeObject(value);
  1. 刷新流以确保所有内容都已发送到客户端:
out.flush();

下面是一个使用对象序列化和HTTP隧道技术的查询查看器的示例,包括 ShowQueries 小程序和 QueryCollection 辅助类:

// ShowQueries.java
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.net.*;

/** Applet reads arrays of strings packaged inside
 *  a QueryCollection and places them in a scrolling
 *  TextArea. The QueryCollection obtains the strings
 *  by means of a serialized object input stream
 *  connected to the QueryGenerator servlet.
 */
public class ShowQueries extends Applet
                         implements ActionListener, Runnable {
    private TextArea queryArea;
    private Button startButton, stopButton, clearButton;
    private QueryCollection currentQueries;
    private QueryCollection nextQueries;
    private boolean isRunning = false;
    private String address =
        "/servlet/coreservlets.QueryGenerator";
    private URL currentPage;

    public void init() {
        setBackground(Color.white);
        setLayout(new BorderLayout());
        queryArea = new TextArea();
        queryArea.setFont(new Font("Serif", Font.PLAIN, 14));
        add(queryArea, BorderLayout.CENTER);
        Panel buttonPanel = new Panel();
        Font buttonFont = new Font("SansSerif", Font.BOLD, 16);
        startButton = new Button("Start");
        startButton.setFont(buttonFont);
        startButton.addActionListener(this);
        buttonPanel.add(startButton);
        stopButton = new Button("Stop");
        stopButton.setFont(buttonFont);
        stopButton.addActionListener(this);
        buttonPanel.add(stopButton);
        clearButton = new Button("Clear TextArea");
        clearButton.setFont(buttonFont);
        clearButton.addActionListener(this);
        buttonPanel.add(clearButton);
        add(buttonPanel, BorderLayout.SOUTH);
        currentPage = getCodeBase();
        // Request a set of sample queries. They
        // are loaded in a background thread, and
        // the applet checks to see if they have finished
        // loading before trying to extract the strings.
        currentQueries = new QueryCollection(address, currentPage);
        nextQueries = new QueryCollection(address, currentPage);
    }

    /** If you press the "Start" button, the system
     *  starts a background thread that displays
     *  the queries in the TextArea. Pressing "Stop"
     *  halts the process, and "Clear" empties the
     *  TextArea.
     */
    public void actionPerformed(ActionEvent event) {
        if (event.getSource() == startButton) {
            if (!isRunning) {
                Thread queryDisplayer = new Thread(this);
                isRunning = true;
                queryArea.setText("");
                queryDisplayer.start();
                showStatus("Started display thread...");
            } else {
                showStatus("Display thread already running...");
            }
        } else if (event.getSource() == stopButton) {
            isRunning = false;
            showStatus("Stopped display thread...");
        } else if (event.getSource() == clearButton) {
            queryArea.setText("");
        }
    }

    /** The background thread takes the currentQueries
     *  object and every half-second places one of the queries
     *  the object holds into the bottom of the TextArea. When
     *  all of the queries have been shown, the thread copies
     *  the value of the nextQueries object into
     *  currentQueries, sends a new request to the server
     *  in order to repopulate nextQueries, and repeats
     *  the process.
     */
    public void run() {
        while(isRunning) {
            showQueries(currentQueries);
            currentQueries = nextQueries;
            nextQueries = new QueryCollection(address, currentPage);
        }
    }

    private void showQueries(QueryCollection queryEntry) {
        // If request has been sent to server but the result
        // isn’t back yet, poll every second. This should
        // happen rarely but is possible with a slow network
        // connection or an overloaded server.
        while(!queryEntry.isDone()) {
            showStatus("Waiting for data from server...");
            pause(1);
        }
        showStatus("Received data from server...");
        String[] queries = queryEntry.getQueries();
        String linefeed = "\n";
        // Put a string into TextArea every half-second.
        for(int i=0; i<queries.length; i++) {
            if (!isRunning) {
                return;
            }
            queryArea.append(queries[i]);
            queryArea.append(linefeed);
            pause(0.5);
        }
    }

    public void pause(double seconds) {
        try {
            Thread.sleep((long)(seconds*1000));
        } catch(InterruptedException ie) {}
    }
}
// QueryCollection.java
import java.net.*;
import java.io.*;

/** When this class is built, it returns a value
 *  immediately, but this value returns false for isDone
 *  and null for getQueries. Meanwhile, it starts a Thread
 *  to request an array of query strings from the server,
 *  reading them in one fell swoop by means of an
 *  ObjectInputStream. Once they’ve all arrived, they
 *  are placed in the location getQueries returns,
 *  and the isDone flag is switched to true.
 *  Used by the ShowQueries applet.
 */
public class QueryCollection implements Runnable {
    private String[] queries;
    private String[] tempQueries;
    private boolean isDone = false;
    private URL dataURL;

    public QueryCollection(String urlSuffix, URL currentPage) {
        try {
            // Only the URL suffix need be supplied, since
            // the rest of the URL is derived from the current page.
            String protocol = currentPage.getProtocol();
            String host = currentPage.getHost();
            int port = currentPage.getPort();
            dataURL = new URL(protocol, host, port, urlSuffix);
            Thread queryRetriever = new Thread(this);
            queryRetriever.start();
        } catch(MalformedURLException mfe) {
            isDone = true;
        }
    }

    public void run() {
        try {
            tempQueries = retrieveQueries();
            queries = tempQueries;
        } catch(IOException ioe) {
            tempQueries = null;
            queries = null;
        }
        isDone = true;
    }

    public String[] getQueries() {
        return(queries);
    }

    public boolean isDone() {
        return(isDone);
    }
}

综上所述,通过多系统搜索引擎前端和HTTP隧道技术,可以实现高效的客户端与服务器之间的数据交互,根据不同的需求选择合适的方法来处理数据。

查询查看器示例分析

上述的 ShowQueries 小程序和 QueryCollection 辅助类构成了一个查询查看器,它可以展示从服务器获取的查询样本。以下是对这个示例的详细分析:

功能概述

该查询查看器的主要功能是持续显示虚构的 super-search-engine.com 的实时查询样本。用户可以通过点击“Start”按钮启动显示线程,点击“Stop”按钮停止显示,点击“Clear TextArea”按钮清空文本区域。

代码结构分析
  • ShowQueries

    • 继承自 Applet ,实现了 ActionListener Runnable 接口。
    • 包含文本区域 queryArea 和三个按钮 startButton stopButton clearButton
    • init 方法中初始化界面组件,并创建 QueryCollection 对象。
    • actionPerformed 方法处理按钮点击事件,根据不同的按钮执行相应的操作。
    • run 方法是线程的执行体,负责循环显示查询样本。
    • showQueries 方法用于显示查询样本,会等待服务器数据返回后再进行显示。
    • pause 方法用于线程暂停。
  • QueryCollection

    • 实现了 Runnable 接口,用于在后台线程中从服务器获取查询字符串数组。
    • 包含 queries tempQueries 数组,以及 isDone 标志。
    • 在构造方法中创建 URL 对象并启动线程。
    • run 方法执行查询字符串的获取操作,完成后将 isDone 标志设置为 true
    • getQueries 方法返回查询字符串数组。
    • isDone 方法返回 isDone 标志的值。
操作流程
graph LR
    A[用户打开页面] --> B[初始化ShowQueries小程序]
    B --> C[创建QueryCollection对象,发送请求]
    D[用户点击Start按钮] --> E[启动显示线程]
    E --> F{当前Queries是否加载完成}
    F -- 是 --> G[显示查询样本]
    F -- 否 --> H[等待数据,每秒检查一次]
    G --> I{所有查询样本显示完?}
    I -- 是 --> J[复制nextQueries到currentQueries]
    J --> K[发送新请求给服务器,重新填充nextQueries]
    K --> F
    I -- 否 --> G
    L[用户点击Stop按钮] --> M[停止显示线程]
    N[用户点击Clear按钮] --> O[清空文本区域]
总结与建议

通过上述的多系统搜索引擎前端和HTTP隧道技术的实现,我们可以看到在Web开发中,客户端与服务器之间的数据交互有多种方式可供选择。

多系统搜索引擎前端
  • 优点 :可以同时向多个搜索引擎发送查询请求,方便用户一次性获取多个搜索引擎的结果。
  • 缺点 :依赖HTML框架,兼容性可能存在一定问题。
  • 建议 :可以考虑使用现代的前端框架如React、Vue.js等来替代HTML框架,提高兼容性和用户体验。
HTTP隧道技术
  • 读取二进制或ASCII数据
    • 优点 :可以与任意服务器端程序或静态网页进行交互,适用性强。
    • 缺点 :需要手动解析数据,处理过程相对复杂。
    • 建议 :在处理复杂数据时,可以考虑使用JSON或XML等格式,方便数据的解析和处理。
  • 读取序列化数据结构
    • 优点 :可以直接读取高级数据结构,无需复杂的解析过程。
    • 缺点 :要求服务器端程序也使用Java编写,局限性较大。
    • 建议 :如果需要与其他语言编写的服务器进行交互,可以考虑使用通用的数据交换格式,如JSON。
查询查看器示例
  • 优点 :可以实时显示服务器的查询样本,提供了一种直观的展示方式。
  • 缺点 :依赖于服务器的响应速度,如果服务器响应慢,可能会影响用户体验。
  • 建议 :可以增加缓存机制,减少对服务器的频繁请求;同时,优化线程处理逻辑,提高响应速度。

附录:操作步骤总结

多系统搜索引擎前端操作步骤
  1. 编写 SearchApplet 小程序,实现用户输入收集和URL生成。
  2. 创建 ParallelSearches.html SearchAppletFrame.html 文件,支持小程序的显示。
  3. 部署小程序和HTML文件到Web服务器。
HTTP隧道技术操作步骤
读取二进制或ASCII数据
  1. 创建指向小程序主主机的 URL 对象。
  2. 创建 URLConnection 对象。
  3. 指示浏览器不要缓存URL数据。
  4. 设置所需的HTTP头。
  5. 创建输入流。
  6. 读取文档的每一行。
  7. 关闭输入流。
读取序列化数据结构

客户端
1. 创建指向小程序主主机的 URL 对象。
2. 创建 URLConnection 对象。
3. 指示浏览器不要缓存URL数据。
4. 设置所需的HTTP头。
5. 创建 ObjectInputStream
6. 使用 readObject 读取数据结构。
7. 关闭输入流。

服务器端
1. 指定响应的MIME类型为 application/x-java-serialized-object
2. 创建 ObjectOutputStream
3. 使用 writeObject 写入数据结构。
4. 刷新流以确保所有内容都已发送到客户端。

查询查看器操作步骤
  1. 编写 ShowQueries 小程序和 QueryCollection 辅助类。
  2. 部署小程序和相关类到Web服务器。
  3. 用户打开包含小程序的页面,点击相应按钮进行操作。

通过以上的操作步骤和代码示例,你可以根据自己的需求实现多系统搜索引擎前端和HTTP隧道技术,实现高效的客户端与服务器之间的数据交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值