问题
I am in a really bad situation.
I am using Volley on an Android application with Ruby on Rails JSON API.
Problem is there is a bug with Volley making it unable to correctly identify anything with staus 401. Basically, whenever there is a 401 status, the NetworkResponse is null and VolleyError is of type NoConnectionError.
I have searched a lot and the only way around it is to return 403 instead of 401 which can be identified correctly by Volley.
How can I change status codes on all responses to 403 if they are 401 in rails? I can't control all the actions and return 403 for example in devise premade actions.
Is there a way to finalize responses or something in rails?
回答1:
Since devise is using warden you can create a custom failureapp and set the http status which you want.
In lib/custom_failure.rb
class CustomFailure < Devise::FailureApp
def respond
self.status = 403
self.content_type = 'json'
self.response_body = { error: "Invalid Email or password."}.to_json
end
end
In config/initializers/devise.rb
config.warden do |manager|
manager.failure_app = CustomFailure
end
In config/application.rb
config.autoload_paths << Rails.root.join('lib')
回答2:
401 status code might come with a blank response data and if you check this volley code line 63-75
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
if jsonString is blank it still tries to create a JSONObject from it new JSONObject(jsonString)
which throws a JSONException
You may download volley source code, import it as module in your android studio project, add it dependency and make this correction:
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
// Fix for an error on blank success response
// return Response.success(new JSONObject(jsonString),
// HttpHeaderParser.parseCacheHeaders(response));
if (!jsonString.trim().contentEquals("")) {
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
}
else {
return Response.success(new JSONObject(),
HttpHeaderParser.parseCacheHeaders(response));
}
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
}
To add Volley to your project - clone the Volley repository and set it as a library project
Git clone the repository by typing the following at the command line:
git clone https://android.googlesource.com/platform/frameworks/volley
Import the downloaded source into your app project as an Android library module as described in Create an Android Library.
You may also try Prase 401 volley error message if you don't want a fix inside the imported library:
回答3:
I found a solution to my problem from the Ruby on Rails
backend side that is generalized for the whole application which is required as a lot of controllers would also give 401
and not only devise
.
I have used Rack
middleware by doing the following:
app/middleware/unauthorized_to_forbidden.rb
class UnauthorizedToForbidden
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if(status == 401)
status = 403
end
[status, headers, response]
end
end
config/application.rb
class Application < Rails::Application
config.middleware.use "UnauthorizedToForbidden"
end
Now UnauthorizedToForbidden
is at the bottom of the Rack
stack and gets executed at the very end before the response is actually sent to the user. It basically changes the status code if it's 401
to 403
.
来源:https://stackoverflow.com/questions/38841114/change-status-code-rails