为什么我在 AppEngine 中使用 HttpURLConnection 会得到 ClassCastException?
Why do I get ClassCastException using HttpURLConnection in AppEngine?
我尝试从使用 App Engine 的 GWT 应用程序调用外部 Web 服务(不是我的)。
我知道由于 SOP(同源策略)而无法从客户端执行此操作,而且 RequestBuilder 不是服务器上的解决方案。我也遵循了 the web site and using java.net 上的教程
这是客户
AsyncCallback<CustomObject> callback = new AsyncCallback<CustomObjectCustomObject>() {
@Override
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
@Override
public void onSuccess(CustomObject result) {
// code omitted
}
};
service.callMethod(aString, callback);
这是服务器
try {
String xmlRequest = "xmlToSend";
URL url = new URL("https://www.externalWebService.com");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setAllowUserInteraction(false);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type","application/soap+xml");
conn.setRequestProperty( "Content-length", Integer.toString(xmlRequest.length()));
conn.setRequestProperty("charset", "utf-8");
conn.setConnectTimeout(10000);
OutputStream rawOutStream = conn.getOutputStream();
PrintWriter pw = new PrintWriter(rawOutStream);
pw.print(xmlRequest);
pw.flush();
pw.close();
if(conn.getResponseCode() != 200){
// Something...
}
我一直在 conn.getResponseCode()
遇到同样的错误:
java.lang.ClassCastException: com.google.appengine.repackaged.org.apache.http.message.BasicHttpRequest cannot be cast to com.google.appengine.repackaged.org.apache.http.client.methods.HttpUriRequest
无需发出真正的请求,远程服务运行良好:它能够序列化 return 对象到客户端。该问题与客户端和服务器之间的通信无关,更像是 AppEngine 不支持 HttpURLConnection。但它应该在服务器上(不是吗?)
如有任何想法,我们将不胜感激!提前致谢
您的问题与 GWT 无关:只要您在服务器上 运行,您可以使用任何 'normal' Java 并且它会工作,除非 AppEngine 有限制.
您似乎在 class 中导入了 repackaged
版本的 Apache HttpClient。你不应该这样做:下载你自己的 HttpClient .jar,将它添加到依赖项并使用那个。
AppEngine 在 HttpClient 方面也存在一些问题。有一个可用的适配器 here 可以解决大部分问题。
谢谢@Marcelo,你是对的!
这是我找到的解决方案。
我在构建路径中添加了 httpcore.jar
和 httpclient.jar
并为服务器编写了以下代码(客户端相同):
String xmlRequest = "xmlToSend";
CloseableHttpClient httpclient = HttpClients.custom().build();
//RequestConfig requestConfig = RequestConfig.custom()
// .setConnectionRequestTimeout(10000)
// .build();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out);
writer.write(xmlToSend);
writer.flush();
writer.close();
HttpPost request = new HttpPost("https://www.externalWebService.com/path");
request.setEntity(new ByteArrayEntity(out.toByteArray()));
//request.setConfig(requestConfig);
CloseableHttpResponse response = httpclient.execute(request);
if(response.getStatusLine().getStatusCode() == 200){
// retrieve content with a BufferReader
// from response.getEntity().getContent()
...
}
代码有效并且是最新的。
编辑
这是使用代理时的其余解决方案。我的只处理 NTCredentials,否则可以使用 UsernamePasswordCredentials
。
HttpHost proxy = new HttpHost("addresse.proxy.com", port);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxy),
new NTCredentials(System.getProperty("user.name") + ":" + password));
RequestConfig requestConfig = RequestConfig.custom()
.setProxy(proxy)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultRequestConfig(requestConfig)
.build();
再次感谢您的帮助,我真的很感激!
我尝试从使用 App Engine 的 GWT 应用程序调用外部 Web 服务(不是我的)。
我知道由于 SOP(同源策略)而无法从客户端执行此操作,而且 RequestBuilder 不是服务器上的解决方案。我也遵循了 the web site and using java.net 上的教程
这是客户
AsyncCallback<CustomObject> callback = new AsyncCallback<CustomObjectCustomObject>() {
@Override
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
@Override
public void onSuccess(CustomObject result) {
// code omitted
}
};
service.callMethod(aString, callback);
这是服务器
try {
String xmlRequest = "xmlToSend";
URL url = new URL("https://www.externalWebService.com");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setAllowUserInteraction(false);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type","application/soap+xml");
conn.setRequestProperty( "Content-length", Integer.toString(xmlRequest.length()));
conn.setRequestProperty("charset", "utf-8");
conn.setConnectTimeout(10000);
OutputStream rawOutStream = conn.getOutputStream();
PrintWriter pw = new PrintWriter(rawOutStream);
pw.print(xmlRequest);
pw.flush();
pw.close();
if(conn.getResponseCode() != 200){
// Something...
}
我一直在 conn.getResponseCode()
遇到同样的错误:
java.lang.ClassCastException: com.google.appengine.repackaged.org.apache.http.message.BasicHttpRequest cannot be cast to com.google.appengine.repackaged.org.apache.http.client.methods.HttpUriRequest
无需发出真正的请求,远程服务运行良好:它能够序列化 return 对象到客户端。该问题与客户端和服务器之间的通信无关,更像是 AppEngine 不支持 HttpURLConnection。但它应该在服务器上(不是吗?)
如有任何想法,我们将不胜感激!提前致谢
您的问题与 GWT 无关:只要您在服务器上 运行,您可以使用任何 'normal' Java 并且它会工作,除非 AppEngine 有限制.
您似乎在 class 中导入了 repackaged
版本的 Apache HttpClient。你不应该这样做:下载你自己的 HttpClient .jar,将它添加到依赖项并使用那个。
AppEngine 在 HttpClient 方面也存在一些问题。有一个可用的适配器 here 可以解决大部分问题。
谢谢@Marcelo,你是对的!
这是我找到的解决方案。
我在构建路径中添加了 httpcore.jar
和 httpclient.jar
并为服务器编写了以下代码(客户端相同):
String xmlRequest = "xmlToSend";
CloseableHttpClient httpclient = HttpClients.custom().build();
//RequestConfig requestConfig = RequestConfig.custom()
// .setConnectionRequestTimeout(10000)
// .build();
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out);
writer.write(xmlToSend);
writer.flush();
writer.close();
HttpPost request = new HttpPost("https://www.externalWebService.com/path");
request.setEntity(new ByteArrayEntity(out.toByteArray()));
//request.setConfig(requestConfig);
CloseableHttpResponse response = httpclient.execute(request);
if(response.getStatusLine().getStatusCode() == 200){
// retrieve content with a BufferReader
// from response.getEntity().getContent()
...
}
代码有效并且是最新的。
编辑
这是使用代理时的其余解决方案。我的只处理 NTCredentials,否则可以使用 UsernamePasswordCredentials
。
HttpHost proxy = new HttpHost("addresse.proxy.com", port);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxy),
new NTCredentials(System.getProperty("user.name") + ":" + password));
RequestConfig requestConfig = RequestConfig.custom()
.setProxy(proxy)
.build();
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setDefaultRequestConfig(requestConfig)
.build();
再次感谢您的帮助,我真的很感激!