简体   繁体   中英

Change status code Rails

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?

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')

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

  1. Git clone the repository by typing the following at the command line:

    git clone https://android.googlesource.com/platform/frameworks/volley

  2. 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:

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM