当前位置: 首页 > 知识库问答 >
问题:

Ruby中的Google Translate API调用生成“URL太大”错误

柳绪
2023-03-14

以下 Ruby 代码访问 Google Translate 的 API:

require 'google/api_client'
client = Google::APIClient.new
translate = client.discovered_api('translate','v2')
client.authorization.access_token = '123' # dummy
client.key = "<My Google API Key>"
response = client.execute(
               :api_method => translate.translations.list,
               :parameters => {
                 'format' => 'text',
                 'source' => 'eng',
                 'target' => 'fre',
                 'q' => 'This is the text to be translated'
                 }
               )

响应以JSON格式返回。

此代码适用于少于大约 750 个字符的待翻译文本(q 参数),但对于较长的文本,将生成以下错误:

错误414(请求URI太大)!!1Error 414(请求URI太大)!!1

我用谷歌搜索了这个问题,发现了以下页面:

https://developers.google.com/translate/ https://github.com/google/google-api-ruby-client

似乎Google API客户端代码使用GET而不是POST来调用Google API。由于各种系统对URL的长度有限制,这就限制了可以翻译的文本的长度。

这个问题的解决方案似乎是,我应该指示Google API接口使用POST而不是GET来调用Google API。然而,我到目前为止还没能想出如何做到这一点。

我看到在其他语言中还有其他一些与此问题相关的StackOverflow问题。但是,到目前为止,我还没有弄清楚如何将其应用于我的Ruby代码。

非常感谢戴夫·萨格。您的方法很有效,我已经将它开发成一个工作示例,其他堆栈溢出用户可能会发现它很有用。(注意:Stack Overflow不会让我在八个小时内将此作为答案发布,所以我改为编辑我的问题。)下面是例子:

#!/usr/local/rvm/rubies/ruby-1.9.3-p194/bin/ruby
#
# This is a self-contained Unix/Linux Ruby script.
#
# Replace the first line above with the location of your ruby executable. e.g.
#!/usr/bin/ruby
#
################################################################################
#
# Author  : Ross Williams.
# Date    : 1 January 2014.
# Version : 1.
# Licence : Public Domain. No warranty or liability.
# 
# WARNING: This code is example code designed only to help Stack Overflow
# users solve a specific problem. It works, but it does not contain
# comprehensive error checking which would probably double the length
# of the code.

require 'uri'
require 'net/http'
require 'net/https'
require 'rubygems'
require 'json'

################################################################################
#
# This method translates a string of up to 5K from one language to another using
# the Google Translate API.
# 
# google_api_key
#    This is a string of about 39 characters which identifies you
#    as a user of the Google Translate API. At the time of writing,
#    this API costs US$20/MB of source text. You can obtain a key
#    by registering at:
#       https://developers.google.com/translate/
#       https://developers.google.com/translate/v2/getting_started
#
# source_language_code
# target_language_code
#    These arguments identify the source and target language.
#    Each of these arguments should be a string containing one
#    of Google's two-letter language identification codes.
#    A list of these codes can be found at:
#       https://sites.google.com/site/opti365/translate_codes
#
# text_to_be_translated
#    This is a string to be translated. Ruby provides excellent
#    Unicode support and this string can contain non-ASCII characters.
#    This string must not be longer than 5K characters long.
#
def google_translate(google_api_key,source_language_code,target_language_code,text_to_be_translated)

   # Note:  The 5K limit on text_to_be_translated is stated at:
   # https://developers.google.com/translate/v2/using_rest?hl=ja
   # It is not clear to me whether this is 5*1024 or 5*1000.

   # The Google Translate API is served at this HTTPS address.
   # See http://stackoverflow.com/questions/13152264/sending-http-post-request-in-ruby-by-nethttp
   uri = URI.parse("https://www.googleapis.com/language/translate/v2")
   request = Net::HTTP::Post.new(uri.path)

   # The API accepts only the GET method. However, the GET method has URL length
   # limitations so we have to use POST method instead. We need to use a trick for
   # deliverying the form fields using POST but having the API perceive it as a GET.
   # Setting a key/value pair in request adds a field to the HTTP header to do this.
   request['X-HTTP-Method-Override'] = 'GET'

   # Load the arguments to the API into the POST form fields.
   params = {
      'access_token' => '123',           # Dummy parameter seems to be required.
      'key'          => google_api_key,
      'format'       => 'text',
      'source'       => source_language_code,
      'target'       => target_language_code,
      'q'            => text_to_be_translated
      }
   request.set_form_data(params)

   # Execute the request.
   # It's important to use HTTPS, as the API key is being transmitted.
   https = Net::HTTP.new(uri.host,uri.port)
   https.use_ssl = true
   response = https.request(request)

   # The API returns a record in JSON format.
   # See http://en.wikipedia.org/wiki/JSON
   # See http://www.json.org/
   json_text = response.body

   # Parse the JSON record, yielding a nested hash/list data structure.
   json_structure = JSON.parse(json_text)

   # Navigate down into the data structure to get the result.
   # This navigation was coded by examining the JSON text from an actual run.
   data_hash = json_structure['data']
   translations_list = data_hash['translations']
   translation_hash = translations_list[0]
   translated_text = translation_hash['translatedText']
   return translated_text

end # def google_translate

################################################################################

google_api_key = '<INSERT YOUR GOOGLE TRANSLATE API KEY HERE>'
source_language_code = 'en' # English
target_language_code = 'fr' # French

# To test the code, I have chosen a sample text of about 3393 characters.
# This is large enough to exceed the GET URL length limit, but small enough
# not to exceed the Google Translate API length limit of 5K.
# Sample text is from http://www.gutenberg.org/cache/epub/2701/pg2701.txt
text_to_be_translated = <<END
Call me Ishmael. Some years ago--never mind how long precisely--having
little or no money in my purse, and nothing particular to interest me on
shore, I thought I would sail about a little and see the watery part of
the world. It is a way I have of driving off the spleen and regulating
the circulation. Whenever I find myself growing grim about the mouth;
whenever it is a damp, drizzly November in my soul; whenever I find
myself involuntarily pausing before coffin warehouses, and bringing up
the rear of every funeral I meet; and especially whenever my hypos get
such an upper hand of me, that it requires a strong moral principle to
prevent me from deliberately stepping into the street, and methodically
knocking people's hats off--then, I account it high time to get to sea
as soon as I can. This is my substitute for pistol and ball. With a
philosophical flourish Cato throws himself upon his sword; I quietly
take to the ship. There is nothing surprising in this. If they but knew
it, almost all men in their degree, some time or other, cherish very
nearly the same feelings towards the ocean with me.

There now is your insular city of the Manhattoes, belted round by
wharves as Indian isles by coral reefs--commerce surrounds it with
her surf. Right and left, the streets take you waterward. Its extreme
downtown is the battery, where that noble mole is washed by waves, and
cooled by breezes, which a few hours previous were out of sight of land.
Look at the crowds of water-gazers there.

Circumambulate the city of a dreamy Sabbath afternoon. Go from Corlears
Hook to Coenties Slip, and from thence, by Whitehall, northward. What
do you see?--Posted like silent sentinels all around the town, stand
thousands upon thousands of mortal men fixed in ocean reveries. Some
leaning against the spiles; some seated upon the pier-heads; some
looking over the bulwarks of ships from China; some high aloft in the
rigging, as if striving to get a still better seaward peep. But these
are all landsmen; of week days pent up in lath and plaster--tied to
counters, nailed to benches, clinched to desks. How then is this? Are
the green fields gone? What do they here?

But look! here come more crowds, pacing straight for the water, and
seemingly bound for a dive. Strange! Nothing will content them but the
extremest limit of the land; loitering under the shady lee of yonder
warehouses will not suffice. No. They must get just as nigh the water
as they possibly can without falling in. And there they stand--miles of
them--leagues. Inlanders all, they come from lanes and alleys, streets
and avenues--north, east, south, and west. Yet here they all unite.
Tell me, does the magnetic virtue of the needles of the compasses of all
those ships attract them thither?

Once more. Say you are in the country; in some high land of lakes. Take
almost any path you please, and ten to one it carries you down in a
dale, and leaves you there by a pool in the stream. There is magic
in it. Let the most absent-minded of men be plunged in his deepest
reveries--stand that man on his legs, set his feet a-going, and he will
infallibly lead you to water, if water there be in all that region.
Should you ever be athirst in the great American desert, try this
experiment, if your caravan happen to be supplied with a metaphysical
professor. Yes, as every one knows, meditation and water are wedded for
ever.
END

translated_text =
   google_translate(google_api_key,
                    source_language_code,
                    target_language_code,
                    text_to_be_translated)

puts(translated_text)

################################################################################

共有1个答案

费锋
2023-03-14

我会直接使用< code>REST API,而不是整个Google API,后者似乎包含了所有内容,但当我在源代码中搜索“translate”时,什么也没找到。

创建一个请求,根据这些文档设置适当的标头

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

代码(未测试)可能看起来像

  require 'net/http'
  require 'net/https'

  uri = URI.parse('https://www.googleapis.com/language/translate/v2')
  request = Net::HTTP::Post.new(uri, {'X-HTTP-Method-Override' => 'GET'})
  params = {
   'format' => 'text',
   'source' => 'eng',
   'target' => 'fre',
   'q' => 'This is the text to be translated'
   }
  request.set_form_data(params)
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  response = https.request request
  parsed = JSON.parse(response)
 类似资料:
  • 我已经使用CXF2.7.3生成了从wsdl到java的代码,但是在构建程序集时,我得到了“代码太大”的错误。指示其中一个方法已超过Java64KB限制。我很清楚是哪个类,对我来说,这似乎是CXF中的bug。Actully Axis2也这样做,所以我想知道是否有人知道如何解决这个问题。 如何强制代码生成拆分大型生成方法?或者我应该使用一些外部工具吗?

  • 简介 Laravel 提供了几个辅助函数来为应用程序生成 URL。主要用于在模板和 API 响应中构建 URL 或者在应用程序的其它部分生成重定向响应。 基础 生成基础 URL 辅助函数 url 可以用于应用的任何一个 URL。生成的 URL 将自动使用当前请求中的方案( HTTP 或 HTTPS )和主机: $post = App\Post::find(1); echo url("/posts

  • URL 生成 我们推荐使用助手函数 url 进行 url 的生成: url('portal/List/index',['id'=>1,'name'=>'cmf5']); url('portal/List/index','id=1&name=cmf5'); 生成美化的 URL 这个功能要在后台URL 美化里增加相应的 url美化规则,用法和 url方法类似 cmf_url('portal/List

  • ThinkCMF遵循ThinkPHP的url生成方法: U方法的定义规则如下(方括号内参数根据实际应用决定): U('地址表达式',['参数'],['伪静态后缀'],['是否显示域名']) U('Blog/Index/index') // 生成Blog应用Index控制器的index操作的URL地址 U('Portal/Article/index?id=1') // 生成Portal应用Artic

  • URL 生成 我们推荐使用助手函数 url 进行 url 的生成: url('portal/List/index',['id'=>1,'name'=>'cmf']); url('portal/List/index','id=1&name=cmf'); 生成美化的 URL 这个功能要在后台URL 美化里增加相应的 url美化规则,用法和 url方法类似 但请写全第一个参数并注意大小写,格式:应用