草庐IT

java - Java SDK for REST API服务上的错误处理

coder 2023-05-18 原文

我们正在构建Java SDK,以简化对提供REST API的一项服务的访问。该SDK将由第三方开发人员使用。我正在努力寻找最佳模式来在SDK中实现更适合Java语言的错误处理。

假设我们有其余端点:GET /photos/{photoId}
这可能会返回以下HTTP状态代码:

  • 401:用户未通过身份验证
  • 403:用户无权访问此照片
  • 404:没有带有该ID的照片

  • 该服务如下所示:
    interface RestService {   
        public Photo getPhoto(String photoID);
    } 
    

    在上面的代码中,我还没有解决错误处理问题。我显然想为sdk的客户提供一种方法,以了解发生了什么错误,并有可能从中恢复。 Java中的错误处理是使用Exception完成的,让我们开始吧。但是,使用异常执行此操作的最佳方法是什么?

    1.包含有关错误信息的单个异常。
    public Photo getPhoto(String photoID) throws RestServiceException;
    
    public class RestServiceException extends Exception {
        int statusCode;
    
        ...
    }
    

    然后,SDK的客户端可以执行以下操作:
    try {
        Photo photo = getPhoto("photo1");
    }
    catch(RestServiceException e) {
        swtich(e.getStatusCode()) {
            case 401 : handleUnauthenticated(); break;
            case 403 : handleUnauthorized(); break;
            case 404 : handleNotFound(); break;
        }
    }
    

    但是我真的不喜欢这个解决方案,主要有两个原因:
  • 通过查看方法的签名,开发人员不知道他可能需要处理哪种错误情况。
  • 开发人员需要直接处理HTTP状态代码,并在此方法的上下文中了解它们的含义(很明显,如果正确使用了它们,很多时候它的含义是已知的,但是并非总是如此) 。

  • 2.具有错误的类层次结构

    方法签名保持不变:
    public Photo getPhoto(String photoID) throws RestServiceException;
    

    但是现在我们为每种错误类型创建异常:
    public class UnauthenticatedException extends RestServiceException;
    public class UnauthorizedException extends RestServiceException;
    public class NotFoundException extends RestServiceException;
    

    现在,SDK的客户端可以执行以下操作:
    try {
        Photo photo = getPhoto("photo1");
    }
    catch(UnauthenticatedException e) {
        handleUnauthorized();
    }
    catch(UnauthorizedException e) {
        handleUnauthenticated();
    }
    catch(NotFoundException e) {
        handleNotFound();
    }
    

    使用这种方法,开发人员无需了解生成错误的HTTP状态代码,他只需要处理Java异常。另一个优点是,开发人员仅可以捕获要处理的异常(与之前必须捕获单个Exception(RestServiceException)然后仅决定是否要处理的异常的先前情况不同)。

    但是,仍然存在一个问题。通过查看方法的签名,开发人员仍然不知道他可能需要处理的错误类型,因为我们在方法的签名中只有父类(super class)。

    3.具有错误的类层次结构,并在方法的签名中列出错误

    好的,所以现在想到的是将方法的签名更改为:
    public Photo getPhoto(String photoID) throws UnauthenticatedException, UnauthorizedException, NotFoundException;
    

    但是,将来有可能将新的错误情况添加到此其余端点。这意味着向方法的签名添加新的Exception,这将是对Java api的重大更改。我们希望有一个更健壮的解决方案,在上述情况下不会导致破坏api的更改。

    4.具有错误的类层次结构(使用未经检查的异常),并在方法的签名中列出它们

    那么,未检查的异常呢?如果我们更改RestServiceException以扩展RuntimeException:
    public class RestServiceException extends RuntimeException
    

    并且我们保留了方法的签名:
    public Photo getPhoto(String photoID) throws UnauthenticatedException, UnauthorizedException, NotFoundException;
    

    这样,我可以在不破坏现有代码的情况下向方法的签名添加新的异常。
    但是,使用此解决方案,开发人员不会被迫捕获任何异常,并且在认真阅读文档(是的,对!)或注意到方法签名中的异常之前,他不会注意到需要处理的错误情况。

    在这种情况下进行错误处理的最佳实践是什么?

    我提到的替代品还有其他(更好的)替代品吗?

    最佳答案

    我看过结合您建议2和3的库,例如

    public Photo getPhoto(String photoID) throws RestServiceException, UnauthenticatedException, UnauthorizedException, NotFoundException;
    

    这样,当您添加扩展了RestServiceException的新的已检查异常时,您无需更改方法的协定,并且使用该协定的任何代码仍然可以编译。

    与回调或未经检查的异常解决方案相比,优点是可以确保您的新错误将由客户端代码处理,即使只是一般错误也是如此。在回调中,将不会发生任何事情,并且如果发生未经检查的异常,则客户端应用程序可能会崩溃。

    关于java - Java SDK for REST API服务上的错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19315263/

    有关java - Java SDK for REST API服务上的错误处理的更多相关文章

    1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    3. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

      大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

    4. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    5. java - 等价于 Java 中的 Ruby Hash - 2

      我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

    6. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

      最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

    7. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

      我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

    8. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

      在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

    9. ruby-on-rails - openshift 上的 rails 控制台 - 2

      我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

    10. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

      我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

    随机推荐