Intranet站点有一个搜索表单,该表单使用AJAX调用不同域上的servlet以获取搜索建议。
这适用于Internet Explorer,Intranet域是“受信任的站点”,并且为受信任的站点启用了跨域请求,但在Firefox中不起作用。
我试图通过在Intranet服务器上创建一个servlet来解决这个问题,所以在同一个域上有一个对我的servlet的JS调用,然后我的servlet调用另一个域上的建议servlet。跨域调用是服务器端的,因此无论浏览器设置如何,都应该可以正常工作。
AJAX调用和我的servlet对另一个servlet的调用都使用带有URL参数的HTTP POST请求和空请求内容。
我坚持使用POST请求的原因是JS代码全部在搜索服务器上的文件中,我无法修改,并且该代码使用POST请求。
我尝试使用GET请求调用客户现有的建议servlet,并产生404错误。
问题是结果不一致。
我使用System.out.println
次调用来显示服务器日志中结果的完整URL和大小。
输出首先似乎会根据调用的浏览器和/或网站而改变,但现在看来甚至会在同一浏览器的会话之间发生变化。
E.g。在搜索框中输入“g”,我使用Firefox在开发环境的前几次尝试中得到了这个输出:
Search suggestion URL: http://searchdev.companyname.com.au/suggest?q=g&max=10&site=All&client=ie&access=p&format=rich
Search suggestion result length: 64
在测试环境(不同的Intranet服务器但相同的搜索服务器)上使用Firefox进行的初始尝试为同一搜索URL生成了0的结果长度。
Internet Explorer的初始尝试在两种环境中都产生了0的结果长度。
然后我尝试搜索不同的字母,发现当“g”没有时,“t”在IE中产生了结果。
关闭浏览器并暂停一段时间后,我再次尝试并获得了不同的结果。
E.g。使用Firefox并在开发环境中尝试“g”现在在以前生成一个时不会产生任何结果。
这种不一致使我觉得我的servlet代码有问题,如下所示。可能导致问题的原因是什么?
我认为搜索建议是由Google Search Appliance提供的,搜索服务器上的JS文件似乎都来自Google。
实际的AJAX调用是在一个文件中的这一行:
XH_XmlHttpPOST(xmlhttp, url, '', handler);
XH_XmlHttpPOST函数在另一个文件中如下:
function XH_XmlHttpPOST(xmlHttp, url, data, handler) {
xmlHttp.open("POST", url, true);
xmlHttp.onreadystatechange = handler;
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length",
/** @type {string} */ (data.length));
XH_XmlHttpSend(xmlHttp, data);
}
这是我的servlet代码:
package com.companyname.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet {
Properties props=null;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String result = "";
String args = req.getQueryString();
String baseURL = props.getProperty("searchFormBaseURL");
String urlStr = baseURL + "/suggest?" + args;
System.out.println("Search suggestion URL: " + urlStr);
try {
int avail, rCount;
int totalCount = 0;
byte[] ba = null;
byte[] bCopy;
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write("".getBytes());
os.close();
InputStream is = conn.getInputStream();
while ((avail = is.available()) > 0) {
if (ba == null) ba = new byte[avail];
else if (totalCount + avail > ba.length) {
// Resize ba if there's more data available.
bCopy = new byte[totalCount + avail];
System.arraycopy(ba, 0, bCopy, 0, totalCount);
ba = bCopy;
bCopy = null;
}
rCount = is.read(ba, totalCount, avail);
if (rCount < 0) break;
totalCount += rCount;
}
is.close();
conn.disconnect();
result = (ba == null ? "" : new String(ba));
System.out.println("Search suggestion result length: " + Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw = resp.getWriter();
pw.print(result);
}
@Override
public void init() throws ServletException {
super.init();
InputStream stream = this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props = new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
答案 0 :(得分:1)
解决方案:不要依赖InputStream.available()
。
该方法的JavaDoc表示它总是返回0
HttpURLConnection.getInputStream()
实际上返回一个HttpInputStream,其中available()
似乎有效,但显然有时会有更多数据返回0。
我将读取循环更改为根本不使用available()
,现在它始终返回预期结果
工作的servlet在下面。
package com.integral.ie.theme;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class suggest extends HttpServlet implements
javax.servlet.Servlet {
Properties props=null;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//super.doPost(req, resp);
final int maxRead=200;
String result="";
String args=req.getQueryString();
String baseURL=props.getProperty("searchFormBaseURL");
String urlStr=baseURL+"/suggest?"+args;
//System.out.println("Search suggestion URL: "+urlStr);
try {
int rCount=0;
int totalCount=0;
int baLen=maxRead;
byte[] ba=null;
byte[] bCopy;
URL url=new URL(urlStr);
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
// Setting these properties may be unnecessary - just did it
// because the GSA javascript does it.
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length","0");
InputStream is=conn.getInputStream();
ba=new byte[baLen];
while (rCount>=0) {
try {
rCount=is.read(ba,totalCount,baLen-totalCount);
if (rCount>0) {
totalCount+=rCount;
if (totalCount>=baLen) {
baLen+=maxRead;
bCopy=new byte[baLen];
System.arraycopy(ba,0,bCopy,0,totalCount);
ba=bCopy;
bCopy=null;
}
}
} catch(IOException e) {
// IOException while reading - allow the method to return
// anything we've read so far.
}
}
is.close();
conn.disconnect();
result=(totalCount==0?"":new String(ba,0,totalCount));
//System.out.println("Search suggestion result length: "
//+Integer.toString(result.length()));
} catch(MalformedURLException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
PrintWriter pw=resp.getWriter();
pw.print(result);
}
@Override
public void init() throws ServletException {
super.init();
InputStream stream=this.getClass().getResourceAsStream("/WEB-INF/lib/endeavour.properties");
props=new Properties();
try {
props.load(stream);
stream.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
答案 1 :(得分:0)
从单元测试开始。 Servlet很容易进行单元测试,而HttpUnit对我们有用。
在浏览器中调试Servlet代码并使用println调用将花费更多时间从长远来看,SO上的某些人很难消化所有这些信息来帮助您。
另外,请考虑使用JavaScript框架(如JQuery)进行AJAX调用。在我看来,没有理由直接触摸xmlHttp对象,因为框架会为你隐藏它。