升级Ubuntu16.04后Ruby2.3/Rails的Net::URI无法处理无效URL
Hey there! Let's break down why your code is still crashing even after adding exception handling, and how to fix it properly.
The Root Cause
First, let's clarify: a 404 status code is something a server returns when it can't find the requested resource. But when you use a totally fake domain like http://www.examplenotexistingotallyfake.com, the problem happens much earlier—your system can't even resolve the domain to an IP address via DNS. That's why you get a SocketError instead of a 404. Net::HTTP never gets to send a request to a server, so there's no HTTP status code to grab.
What's Wrong With Your Current Fix?
Your modified get_url_response method catches the SocketError, but after logging the error, it doesn't return anything (implicitly returns nil). Later, when your code tries to call .code on the result of get_url_response, you'll get a new error: undefined method 'code' for nil:NilClass—which is why your app still crashes.
The Proper Solution
We need to:
- Catch all likely network-related exceptions (not just
SocketError). - Return a consistent structure that your downstream code can safely use, even when an error occurs.
Here's a revised version of your code:
Step 1: Update the get_url_response Method
def get_url_response(url) uri = URI(url) request = Net::HTTP.get_response(uri) # Return a hash with success details { status_code: request.code, error: nil } rescue SocketError, Timeout::Error, Errno::ECONNREFUSED, Net::HTTPBadResponse => e # Handle DNS failures, timeouts, connection refusals, and invalid responses { status_code: "503", error: "Network error: #{e.message}" } rescue => e # Catch any other unexpected errors as a fallback { status_code: "500", error: "Unexpected error: #{e.message}" } end
Step 2: Update the Calling Code
url_result = get_url_response("http://www.examplenotexistingotallyfake.com") if ["200", "304"].include?(url_result[:status_code]) link_to "http://www.example.com", "http://www.example.com", target: :blank else error_message = "We have a problem! Response code: #{url_result[:status_code]}. #{url_result[:error]}" status_tag(error_message, class: 'red') end
Why This Works
- Comprehensive Exception Handling: We catch all common network issues that can prevent a request from completing, not just DNS failures.
- Consistent Return Structure: The method always returns a hash with
status_codeanderrorkeys, so your downstream code never tries to call methods onnil. - Clear Error Messaging: The admin gets specific details about what went wrong, not just a generic failure.
Checking Your DNS Configuration
If you still suspect your Ubuntu 16.04 DNS changes are causing issues, test this in your terminal:
ping examplenotexistingotallyfake.com
If it returns unknown host, your DNS is working correctly (it's properly identifying that the domain doesn't exist). If you get a different error (like timeouts without the "unknown host" message), then you might need to check your /etc/resolv.conf or network settings.
内容的提问来源于stack exchange,提问作者Mathieu

