部署在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.parseand deprecated methods likeURI.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:
URI.escapeis deprecated (since Ruby 2.7) and doesn't follow modern URL encoding standards consistently.- 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_NONEdisables SSL certificate validation, which is a security risk in production. Make sure to switch toVERIFY_PEERonce 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
相关产品推荐
相关产品推荐

