10

JVM 新手,使用 Scala 和 Play 2.0

我正在将一个遗留应用程序转换为 Play,它需要通过 Authorize.net 进行支付处理。查看 java.net.URL 源代码,有许多潜在的故障点。鉴于我在下面编写的接口,您将在哪里实现 try/catch 块?我需要相应地调整方法签名,可能会返回一个 Either[Error, Success] 来调用客户端代码

import java.net.{URL, URLEncoder}
import java.io.{BufferedReader, DataOutputStream, InputStreamReader}
import javax.net.ssl._

trait Authnet {
  private val prodUrl = "https://secure.authorize.net/gateway/transact.dll"
  private val testUrl = "https://test.authorize.net/gateway/transact.dll"

  protected def authNetProcess(params: Map[String,String]) = {
    val(conn, urlParams) = connect(params)
    val request = new DataOutputStream( conn.getOutputStream )
    request.write(urlParams.getBytes)
    request.flush()
    request.close()
    val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
    val results = response.readLine().split("\\|")
    response.close()
    results.toList
  }  

  private def connect(params: Map[String,String]) = {
    val urlParams = (config ++ params) map { case(k,v) =>
        URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(v, "UTF-8")
    } mkString("&")

    lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
    val conn = url.openConnection
    conn.setDoOutput(true)
    conn.setUseCaches(false)
    (conn, urlParams)
  }

  private val config = Map(
    'x_login        -> "...",
    'x_tran_key     -> "...",
    ...
  )
}
4

2 回答 2

1

坚持拇指规则:

仅在必须处理异常时才捕获异常。

“必须处理”没有明确的定义,但这意味着您应该抵制捕获异常的冲动,因为您可以抛出不同的异常。

“必须处理”主要由您的应用程序应该如何工作或其他依赖项定义。

如果应用程序需要向用户显示错误而不是异常中止,那么这是必须的。

在这种情况下,捕捉异常也会增加一些有意义的处理。

如果 API 需要抛出不同的异常,那么这是必须的,但 API 的定义可能不合理。

我总是质疑用另一个异常替换一个异常的附加价值。

将此应用于您的示例:

它会增加一些价值来从 authNetProcess() 中的 connect() 捕获异常吗?

不!在 connect() 中无法处理该异常。因此,可以将该异常留给 authNetProcess 的调用者。在那里,您可以根据异常的类型提供不同的处理。

于 2012-06-10T10:03:24.047 回答
0

编辑
好吧,如果连接/流过程的任何部分失败,事务就会被冲洗掉,所以只在打开连接时捕获错误是很愚蠢的。我只是将整个交易包装在一个catching (operation) option块中,然后将其保留;我不太担心:错误的确切原因(无论是什么被记录)因为它是暂时的,所以抓住它,让用户再试一次;如果错误仍然存​​在,请联系我们...

原创 好的,好吧,鉴于迄今为止的投票和缺乏评论,我能得出的唯一结论是......这里没有人知道他们在做什么!嘿嘿,开玩笑的 ;-)

虽然我是 JVM 新手,但 try/catch/finally bloat 很快就会变老;通过 Scala 类型推断的奇迹,我将一般错误处理抽象为简洁的实现:
catching ( operation ) option
catching ( operation ) either

除非我收到其他反馈,否则现在我只是通过捕获连接创建来解决问题(我相信,在这种情况下,最有可能的错误情况)。这是新的实现:

protected def authNetProcess(params: Map[String,String]) = {
    connect() match {
      case Some(conn) =>
        val request = new DataOutputStream(conn.getOutputStream)
        request.write(getUrlParams(params).getBytes)
        request.flush()
        request.close()
        val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
        val results = response.readLine().split("\\|")
        response.close()
        results.toList
      case None => List[String]()
    }
  }

  private def connect() = {
    lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
    catching ( url.openConnection ) option match {
      case Some(conn) =>
        conn.setDoOutput(true)
        conn.setUseCaches(false)
        //conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
        Some(conn)
      case None => None // connection failed
    }
  }

我想一种更严格的方法是将所有潜在的错误条件提取到可能工作的选项操作中,然后将它们全部包装在一个理解中。这可能是正确/负责任的方法......但一天只有这么多小时,稍后会重新审视

反馈赞赏!

于 2012-06-01T15:51:47.850 回答