从 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.