多系统搜索引擎前端与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);
-
创建一个
URLConnection对象:
URLConnection connection = dataURL.openConnection();
- 指示浏览器不要缓存URL数据:
connection.setUseCaches(false);
- 设置任何所需的HTTP头:
connection.setRequestProperty("header", "value");
- 创建一个输入流:
BufferedReader in =
new BufferedReader(new InputStreamReader(
connection.getInputStream()));
- 读取文档的每一行:
String line;
while ((line = in.readLine()) != null) {
doSomethingWith(line);
}
- 关闭输入流:
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);
-
创建一个
URLConnection对象:
URLConnection connection = dataURL.openConnection();
- 指示浏览器不要缓存URL数据:
connection.setUseCaches(false);
- 设置任何所需的HTTP头:
connection.setRequestProperty("header", "value");
-
创建一个
ObjectInputStream:
ObjectInputStream in =
new ObjectInputStream(connection.getInputStream());
-
使用
readObject读取数据结构:
SomeClass value = (SomeClass)in.readObject();
doSomethingWith(value);
- 关闭输入流:
in.close();
服务器端步骤
:
1. 指定正在发送二进制内容,将响应的MIME类型指定为
application/x-java-serialized-object
:
String contentType =
"application/x-java-serialized-object";
response.setContentType(contentType);
-
创建一个
ObjectOutputStream:
ObjectOutputStream out =
new ObjectOutputStream(response.getOutputStream());
-
使用
writeObject写入数据结构:
SomeClass value = new SomeClass(...);
out.writeObject(value);
- 刷新流以确保所有内容都已发送到客户端:
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。
查询查看器示例
- 优点 :可以实时显示服务器的查询样本,提供了一种直观的展示方式。
- 缺点 :依赖于服务器的响应速度,如果服务器响应慢,可能会影响用户体验。
- 建议 :可以增加缓存机制,减少对服务器的频繁请求;同时,优化线程处理逻辑,提高响应速度。
附录:操作步骤总结
多系统搜索引擎前端操作步骤
-
编写
SearchApplet小程序,实现用户输入收集和URL生成。 -
创建
ParallelSearches.html和SearchAppletFrame.html文件,支持小程序的显示。 - 部署小程序和HTML文件到Web服务器。
HTTP隧道技术操作步骤
读取二进制或ASCII数据
-
创建指向小程序主主机的
URL对象。 -
创建
URLConnection对象。 - 指示浏览器不要缓存URL数据。
- 设置所需的HTTP头。
- 创建输入流。
- 读取文档的每一行。
- 关闭输入流。
读取序列化数据结构
客户端
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. 刷新流以确保所有内容都已发送到客户端。
查询查看器操作步骤
-
编写
ShowQueries小程序和QueryCollection辅助类。 - 部署小程序和相关类到Web服务器。
- 用户打开包含小程序的页面,点击相应按钮进行操作。
通过以上的操作步骤和代码示例,你可以根据自己的需求实现多系统搜索引擎前端和HTTP隧道技术,实现高效的客户端与服务器之间的数据交互。
多系统搜索引擎前端与HTTP隧道技术应用
超级会员免费看

被折叠的 条评论
为什么被折叠?



