You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署在Google Cloud的Rails应用:URI必须仅含ASCII字符问题

URI::InvalidURIError "URI must be ascii only" in Rails Production on GCP (works locally/Postman)

Let's break down why this is happening and fix it properly.

First, why the environment difference?

  • Postman automatically handles URL encoding for you: when you paste an address with accents like Córsega, Postman converts non-ASCII characters to their percent-encoded equivalents (e.g., ó becomes %C3%B3) before sending the request. That's why it works seamlessly.
  • Local environment: Your local Ruby version or system encoding settings (like a UTF-8 default locale) might be more lenient with unencoded non-ASCII characters in URIs. Older Ruby versions also had less strict behavior around URI.parse and deprecated methods like URI.escape.
  • GCP Production: The Ruby version here is likely newer and enforces strict URI standards—URIs must be ASCII-only, so any unencoded special characters (like accents) will trigger URI::InvalidURIError.

Why your current fix isn't working

Using URI.escape on the entire URL is problematic for two reasons:

  1. URI.escape is deprecated (since Ruby 2.7) and doesn't follow modern URL encoding standards consistently.
  2. Escaping the entire URL can break valid parts of the URI (like ? or & separators) or fail to properly encode parameter values in all cases.

The correct fix

Instead of escaping the whole URL, encode just the address parameter value using URI.encode_www_form_component—this method is designed specifically for encoding form data parameters and follows the application/x-www-form-urlencoded standard, which handles accents and special characters correctly.

Here's the revised code:

def stuart_validate_address(address)
  require 'uri'
  require 'net/http'
  require 'json'

  # Encode only the address parameter value, not the entire URL
  encoded_address = URI.encode_www_form_component(address)
  url = URI.parse("https://api.stuart.com/v2/addresses/validate?type=picking&address=#{encoded_address}")
  
  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  # Important: In production, remove VERIFY_NONE and use VERIFY_PEER for secure SSL validation
  # http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Get.new(url)
  request["authorization"] = "Bearer #{AUTH_TOKEN}"
  # GET requests typically don't need a body—you can safely remove this line unless the API explicitly requires it
  # request.body = "{}"

  response = http.request(request)
  JSON.parse(response.read_body)
end

Bonus notes

  • SSL Security: VERIFY_NONE disables SSL certificate validation, which is a security risk in production. Make sure to switch to VERIFY_PEER once you confirm your GCP environment trusts the Stuart API's SSL certificate.
  • GET Request Body: Most APIs don't expect a body for GET requests. Removing request.body = "{}" avoids potential unexpected behavior from the server.

内容的提问来源于stack exchange,提问作者AlbertMunichMar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 08:48:12