开发者

Making a POST call to Google Translate with Jersey returns HTTP 404

I'm trying to write a POST call to Google Translate with Jersey 1.5. This is my code:

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"));    
    }
}

When I run this, all I get back is this: com.sun.jersey.api.client.UniformInterfaceException: POST https://www.googleapis.com/language/translate/v2 returned a response status of 404.

I've managed to accomplish this wit开发者_Go百科h a simple cURL command like so:

curl --header "X-HTTP-Method-Override: GET" -d key=xxxx -d q=Hello -d source=en -d target=sv https://www.googleapis.com/language/translate/v2

Thanks in advance!


I suspect that POST with zero Content-Length is not something a normal HTTP server will accept. The RFC does not define this case, but the main assumption of POST is that you're sending a message body.

Looking at the Google API, they mention the following

You can also use POST to invoke the API if you want to send more data in a single request. The q parameter in the POST body must be less than 5K characters. To use POST, you must use the X-HTTP-Method-Override header to tell the Translate API to treat the request as a GET (use X-HTTP-Method-Override: GET).

This means that instead of adding q, source and target parameters in the URL, you need to do so in the POST body. I'm not familiar with the Jersey API, from a brief look you just need to add params as an explicit second parameter to the .post call, remove the queryParams() call, and set the Content-Length properly.


I think the best and correct way is this

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;
}


I was able to send very long text like this!

Client:

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);

Server:

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


I switched to Apache HttpClient 4.x and solved it like this instead:

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"));
    }

}

Don't really know why this works better than Jersey, but it works. Thanks for trying to help!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜