从 Java 客户端应用程序 post 到 Google App Engine 上的 servlet 的正确方法
Proper way to post to a servlet on Google App Engine from a Java client application
我已经部署到 App Engine。我设置了 SSL,并将其与自定义域相关联。当我在本地开发应用程序时,通过 http://localhost:8080/servlet 发送到 servlet,按预期工作,但是当我将它部署到 App Engine 时,我还没有得到适当的结果。我已经尝试了很多东西,但我一直收到的响应代码不是 404 就是 500。
我从一个简单的 HTTPUrlConnection 和 DataOutputstream 开始,将 JSON 发送到 servlet,并获得适当的响应。像这样:
URL url;
HttpURLConnection connection = null;
try {
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("custom-Header", "XYZ");
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(urlParameters);
wr.flush ();
wr.close ();
//Get Response
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
}
finally {
if(connection != null) {
connection.disconnect();
}
}
这在本地有效。
我现在尝试了 Apache Common 的 HttpAsyncClient,以检查它是否可能是时间问题:
final ResponseObject responseObject = new ResponseObject(); //my simple POJO
try(CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
.setSSLStrategy(sslSessionStrategy)
.build()) {
httpclient.start();
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json");
post.setHeader("custom-Header", "XYZ");
post.setHeader("Content-Language", "en-US");
HttpEntity entity = new ByteArrayEntity(urlParameters);
post.setEntity(entity);
final CountDownLatch latch1 = new CountDownLatch(1);
httpclient.execute(post, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response) {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
try {
responseObject.message = entity != null ? EntityUtils.toString(entity) : null;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
responseObject.exception = new ClientProtocolException("Unexpected response status: " + status);
}
latch1.countDown();
}
public void failed(final Exception ex) {
responseObject.exception = ex;
latch1.countDown();
}
public void cancelled() {
latch1.countDown();
}
});
latch1.await();
if(responseObject.exception != null) {
throw responseObject.exception;
} else {
return responseObject.message;
}
}
这在本地也有效,但是当尝试连接到 AppEngine 时,仍然不行。
这是我的简单 web.xml:
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>my.servlet.package.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>everything</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
</welcome-file-list>
在本地,我 post 到 http://localhost:8080/login。至于 App Engine,我 posted 到 ff:
我试过更改 url 模式。我从 /login 开始,然后 login,然后明确尝试了 App Engine 和自定义域 urls(即 myapp.appspot.com/login 和 myapp.mydomain.com/login)。在尝试没有与 servlet 关联的实际页面(即 login.jsp 或 login.html 之后,我还尝试将实际的 jsp 或 html 页面设置为 post。
当我使用 HttpAsyncClient(我的选择是由于 SSLContext)时,我得到的最好结果是与 servlet 关联的页面的 HTML,但从来没有我需要的来自 Servlet 的响应。
有什么想法吗?
在 Google 云平台的分散文档之一上找到了答案:
https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled
https://cloud.google.com/appengine/docs/standard/java/how-requests-are-routed
基本上,您必须在项目的 appspot 前面加上 url,例如myapp.appspot.com,以及您应用的任何活跃服务实例的版本 ID。您可以在 App Engine 控制台的版本页面下找到此类 ID。例如:https://versionId.myapp.appspot.com.
我已经部署到 App Engine。我设置了 SSL,并将其与自定义域相关联。当我在本地开发应用程序时,通过 http://localhost:8080/servlet 发送到 servlet,按预期工作,但是当我将它部署到 App Engine 时,我还没有得到适当的结果。我已经尝试了很多东西,但我一直收到的响应代码不是 404 就是 500。
我从一个简单的 HTTPUrlConnection 和 DataOutputstream 开始,将 JSON 发送到 servlet,并获得适当的响应。像这样:
URL url;
HttpURLConnection connection = null;
try {
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("custom-Header", "XYZ");
connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.length));
connection.setRequestProperty("Content-Language", "en-US");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(urlParameters);
wr.flush ();
wr.close ();
//Get Response
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
}
finally {
if(connection != null) {
connection.disconnect();
}
}
这在本地有效。
我现在尝试了 Apache Common 的 HttpAsyncClient,以检查它是否可能是时间问题:
final ResponseObject responseObject = new ResponseObject(); //my simple POJO
try(CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
.setSSLStrategy(sslSessionStrategy)
.build()) {
httpclient.start();
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json");
post.setHeader("custom-Header", "XYZ");
post.setHeader("Content-Language", "en-US");
HttpEntity entity = new ByteArrayEntity(urlParameters);
post.setEntity(entity);
final CountDownLatch latch1 = new CountDownLatch(1);
httpclient.execute(post, new FutureCallback<HttpResponse>() {
public void completed(final HttpResponse response) {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
try {
responseObject.message = entity != null ? EntityUtils.toString(entity) : null;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
responseObject.exception = new ClientProtocolException("Unexpected response status: " + status);
}
latch1.countDown();
}
public void failed(final Exception ex) {
responseObject.exception = ex;
latch1.countDown();
}
public void cancelled() {
latch1.countDown();
}
});
latch1.await();
if(responseObject.exception != null) {
throw responseObject.exception;
} else {
return responseObject.message;
}
}
这在本地也有效,但是当尝试连接到 AppEngine 时,仍然不行。
这是我的简单 web.xml:
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>my.servlet.package.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>everything</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
</welcome-file-list>
在本地,我 post 到 http://localhost:8080/login。至于 App Engine,我 posted 到 ff:
我试过更改 url 模式。我从 /login 开始,然后 login,然后明确尝试了 App Engine 和自定义域 urls(即 myapp.appspot.com/login 和 myapp.mydomain.com/login)。在尝试没有与 servlet 关联的实际页面(即 login.jsp 或 login.html 之后,我还尝试将实际的 jsp 或 html 页面设置为 post。
当我使用 HttpAsyncClient(我的选择是由于 SSLContext)时,我得到的最好结果是与 servlet 关联的页面的 HTML,但从来没有我需要的来自 Servlet 的响应。
有什么想法吗?
在 Google 云平台的分散文档之一上找到了答案: https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled https://cloud.google.com/appengine/docs/standard/java/how-requests-are-routed
基本上,您必须在项目的 appspot 前面加上 url,例如myapp.appspot.com,以及您应用的任何活跃服务实例的版本 ID。您可以在 App Engine 控制台的版本页面下找到此类 ID。例如:https://versionId.myapp.appspot.com.