【问题标题】:Making a POST call to Google Translate with Jersey returns HTTP 404使用 Jersey 对 Google 翻译进行 POST 调用会返回 HTTP 404
【发布时间】:2011-01-21 08:22:45
【问题描述】:

我正在尝试使用 Jersey 1.5 编写对 Google 翻译的 POST 调用。这是我的代码:

package main;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.core.util.MultivaluedMapImpl;

import javax.ws.rs.core.MultivaluedMap;

public class Main {

    private static String GOOGLE_TRANSLATE_URL = "https://www.googleapis.com/language/translate/v2";

    private static String translateString(String sourceString, String sourceLanguage, String targetLanguage) {
        String response;
        Client c = Client.create();

        WebResource wr = c.resource(GOOGLE_TRANSLATE_URL);
        MultivaluedMap<String, String> params = new MultivaluedMapImpl();
        params.add("q", sourceString);
        params.add("source", sourceLanguage);
        params.add("target", targetLanguage);
        params.add("key", "xxxx");
        wr.header("X-HTTP-Method-Override", "GET");
        response = wr.post(String.class, params);

        return response;
    }

    public static void main(String[] args) {
        System.out.println(translateString("Hello", "en", "sv"));    
    }
}

当我运行它时,我得到的只是:com.sun.jersey.api.client.UniformInterfaceException: POST @987654321@ returned a response status of 404

我已经设法通过一个简单的 cURL 命令来完成这个任务,如下所示:

curl --header "X-HTTP-Method-Override: GET" -d key=xxxx -d q=Hello -d source=en -d target=sv @987654322@

提前致谢!

【问题讨论】:

  • 如果你的身体是空的,为什么还要使用 POST?尝试使用 GET。
  • 我之所以要使用 POST 是因为否则我在翻译很长的文本时会受到 URL 长度的限制。 URL 的长度在浏览器和服务器实现之间似乎有很大差异。 boutell.com/newfaq/misc/urllength.html

标签: java http post jersey google-translate


【解决方案1】:

我怀疑内容长度为零的 POST 不是普通 HTTP 服务器可以接受的。 RFC 没有定义这种情况,但 POST 的主要假设是您正在发送消息正文。

查看Google API,他们提到以下内容

如果您想在单个请求中发送更多数据,也可以使用 POST 调用 API。 POST 正文中的 q 参数必须少于 5K 个字符。要使用 POST,您必须使用 X-HTTP-Method-Override 标头告诉 Translate API 将请求视为 GET(使用 X-HTTP-Method-Override: GET)。

这意味着您需要在 POST 正文中添加 q、source 和 target 参数,而不是在 URL 中添加。我对 Jersey API 不熟悉,简单来说,您只需将参数作为显式的第二个参数添加到 .post 调用中,删除 queryParams() 调用,并正确设置 Content-Length。

【讨论】:

  • 感谢您的回复!我已经完成了您所写的操作,将我的 params 变量作为第二个参数添加到 .post() 调用中,并删除了我用来设置 Content-Length 的行。然而,这会呈现一个 UniformInterfaceException 说“返回 404 的响应状态”。
  • 您仍然需要设置 Content-Length 以匹配您发布的数据的长度。我不知道为什么你会得到 404,但无论如何都需要设置 Content-Length。如果还是不行,请附上 Wireshark 的流量捕获,也许这会让我们知道出了什么问题。
  • 您的问题可能是 wr.queryParams(params) 调用 w/POST;它不应该有任何请求参数。否则,我与 RomanK 合作,Wireshark 将消除对请求有效性的任何怀疑(尽管我怀疑 Jersey 会为您处理内容长度)。
  • 解决方案在stackoverflow.com/a/9432636/16673中有详细描述——它是C#,但是很容易适应。
【解决方案2】:

我认为最好和正确的方法是这样

private static final String gurl = "www.googleapis.com";
private static final String gpath = "/language/translate/v2/detect";


public String detectLangGooglePost(String text) throws SystemException {

    List<NameValuePair> qparams = new ArrayList<NameValuePair>();
    qparams.add(new BasicNameValuePair("key", key));

    URI uri;
    try {
        uri = URIUtils.createURI("https", gurl, -1, gpath, URLEncodedUtils.format(qparams, "UTF-8"), null);
    } catch (URISyntaxException e) {
        throw new SystemException("Possibly invalid URI parameters", e);
    }

    HttpResponse response = getPostResponse(uri, text);
    StringBuilder builder = getBuilder(response);
    String language = getLanguage(builder);

    return language;
}

private HttpResponse getPostResponse(URI uri, String text) throws SystemException {

    List<NameValuePair> qparams = new ArrayList<NameValuePair>();
    qparams.add(new BasicNameValuePair("q", text));

    HttpResponse response;
    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(uri);
    httpPost.addHeader("X-HTTP-Method-Override", "GET");
    try {
        httpPost.setEntity(new UrlEncodedFormEntity(qparams));
        response = httpclient.execute(httpPost);
    } catch (Exception e) {
        throw new SystemException("Problem when executing Google get request", e);
    }

    int sc = response.getStatusLine().getStatusCode();
    if (sc != HttpStatus.SC_OK)
        throw new SystemException("google status code : " + sc);
    return response;
}

private StringBuilder getBuilder(HttpResponse response) throws SystemException {
    HttpEntity entity = response.getEntity();
    if (entity == null)
        throw new SystemException("response entity null");

    StringBuilder builder = new StringBuilder();
    BufferedReader in = null;
    String str;
    try {
        in = new BufferedReader(new InputStreamReader(entity.getContent()));
        while ((str = in.readLine()) != null)
            builder.append(str);
    } catch (IOException e) {
        throw new SystemException("Reading input stream of http google response entity problem", e);
    } finally {
        IOUtils.closeQuietly(in);
    }
    if (builder.length() == 0)
        throw new SystemException("content stream of response entity empty has zero length");
    return builder;
}

private String getLanguage(StringBuilder builder) throws SystemException {
    JSONObject data = null;
    JSONArray detections = null;
    String language = null;

    JSONObject object = (JSONObject) JSONValue.parse(builder.toString());
    if (object == null)
        throw new SystemException("JSON parsing builder object returned null");

    if (object.containsKey("data") == false)
        throw new SystemException("JSONObject doesn't contain data key");
    data = (JSONObject) object.get("data");

    detections = (JSONArray) data.get("detections");
    if (detections == null)
        throw new SystemException("JSON detections is null");

    JSONObject body = (JSONObject) ((JSONArray) detections.get(0)).get(0);
    if (body == null)
        throw new SystemException("detections body is null");

    if (body.containsKey("language") == false)
        throw new SystemException("language key is null");
    language = (String) body.get("language");

    if (language == null || language.equals(unknown))
        throw new SystemException("Google lang detection - resulting language : " + language);
    return language;
}

【讨论】:

    【解决方案3】:

    我可以这样发送很长的文本!

    客户:

    MultivaluedMap<String,String> formData = new MultivaluedMapImpl();
    formData.add("text", text);
    
    WebResource resource = Client.create().resource(getBaseURI()).path("text2rdf");
    return resource.type("application/x-www-form-urlencoded").post(String.class, formData);
    

    服务器:

    @POST
    @Produces("text/whatever")
    public String textToRdf (
            @FormParam("text") String text) {...
    

    【讨论】:

    • 不适用于需要 HTTP-Method-Override 的 Google Translate API。
    【解决方案4】:

    我切换到 Apache HttpClient 4.x 并像这样解决它:

    public class Main {
    
        private static String GOOGLE_TRANSLATE_URL = "https://www.googleapis.com/language/translate/v2";
        private static String GOOGLE_API_KEY = "xxxx";
    
        private static String translateString(String sourceString, String sourceLanguage, String targetLanguage) {
    
            String response = null;
    
            // prepare call
            HttpClient client = new DefaultHttpClient();
            HttpPost post = new HttpPost(GOOGLE_TRANSLATE_URL+"?q="+sourceString+"&source="+sourceLanguage+"&target="+targetLanguage+"&key="+GOOGLE_API_KEY);
            post.setHeader("X-HTTP-Method-Override", "GET");
    
            try {
    
                // make the call
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                response = client.execute(post, responseHandler);
    
            } catch (IOException e) {
                // todo: proper error handling
            }
    
            return response;
        }
    
        public static void main(String[] args) {
            System.out.println(translateString("hello", "en", "sv"));
        }
    
    }
    

    真的不知道为什么这比泽西岛更好,但它确实有效。感谢您的帮助!

    【讨论】:

    • 我相信您在这里所做的实际上是一个 POST 请求,其参数不在请求正文中,而是在 URL 中。如果 sourceString 太长会失败 .... 413 状态码 ... 查看 HttpPost 构造函数的 URL 发生了什么
    猜你喜欢
    • 1970-01-01
    • 2014-07-14
    • 2014-04-21
    • 1970-01-01
    • 2019-07-11
    • 2018-08-30
    • 1970-01-01
    • 2018-02-06
    • 2013-08-07
    相关资源
    最近更新 更多