Как я могу обработать 403 секунды с помощью XML.load в Scala?

#xml #scala

#xml #scala

Вопрос:

Я пишу клиент Scala для взаимодействия с API продукта RESTful от Amazon. Чтобы вернуть XML для данного запроса, я использую:

 XML.load(uri)
  

Это работает нормально, за исключением того, что иногда, когда Amazon не нравится, например, подпись, встроенная в uri , и поэтому он возвращает 403 (вместе с допустимым отчетом об ошибке XML). К сожалению, этот 403 выдает исключение внутри XML.load :

 java.io.IOException: Server returned HTTP response code: 403 for URL: http://...
  

В идеале я хотел бы иметь способ помечать исключение, но в любом случае возвращать XML с ошибкой. Есть ли простой способ сделать это с XML.load , которого мне не хватает, или мне нужно будет разбить его на двухэтапный процесс получения и последующей загрузки?

Ответ №1:

XML.load (URL) использует Java java.net.URL.openStream(), который генерирует исключение IOException таким образом, что не дает вам никакого доступа к «Потоку ошибок»

Итак, вы можете выполнить более длинную последовательность вызовов, чтобы получить InputStream, а затем вы можете XML.load этот результирующий InputStream.

Используйте URL.openConnection() (вместо URL.openStream), а затем вызовите HttpURLConnection.getInputStream() из блока try. Затем в вашем блоке catch вызовите HttpURLConnection.getErrorStream() .

http://download.oracle.com/javase/6/docs/api/java/net/URL.html#openConnection()

http://download.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html#getErrorStream()

Теперь вы можете вызвать XML.load (InputStream) для результирующего InputStream.

Надеюсь, этого достаточно, чтобы направить вас в нужное русло.

Комментарии:

1. Большое спасибо за руководство — я реализую его именно так, как вы предлагаете.

Ответ №2:

При отправке http (http://dispatch.databinder.net/About ) это выполнимо следующим образом:

 import dispatch.Http._
import dispatch.{StatusCode, Http}
import xml.XML

try {
  Http("http://localhost/notthere" <> println)
} catch {
  case StatusCode(404, data) =>
    println(XML.loadString(data))
}
  

Комментарии:

1. Спасибо за это — я не слышал о Scala Dispatch, выглядит интересно

Ответ №3:

Это код, который я закончил писать, большое спасибо за все рекомендации выше. (Если что-либо из приведенного ниже можно улучшить / сделать более идиоматичным, пожалуйста, дайте мне знать):

 val url = new URL("http://ecs.amazonaws...")

val connection = url.openConnection() match {
  case x: HttpURLConnection => x
  case _ => throw new ClassCastException
}

val responseCode = connection.getResponseCode();

val data = try {
  connection.getInputStream()
} catch {
  case e => connection.getErrorStream()
}

val xml = XML.load(data)
return (responseCode, xml)
  

Ответ №4:

Для этого уровня управления вы можете использовать ConstructingParser. Пример включен в эту ссылку. Вы получаете raw Source и создаете XML из него в два отдельных этапа, используя эту технику.

Комментарии:

1. Полезный пример, спасибо — я заимствую этот код PrettyPrinter для метода debug () в моем API…

Ответ №5:

Вот мое решение, которому необходимо добавить scalaj в проект.

Шаг 1: добавьте scalaj в build.sbt (моя версия scala — 2.11.7, но там все еще сказано, что моя версия scala была обновлена одной из зависимостей libraray. итак, я добавляю ivyscala для принудительного обновления)

 libraryDependencies  = "org.scalaj" %% "scalaj-http" % "1.1.4"

ivyScala := ivyScala.value map { _.copy(overrideScalaVersion = true) }
  

Шаг 2: импортируйте библиотеку в код

 import scalaj.http.Http
import scala.xml.XML
  

Шаг 3: используйте тело http, чтобы избавиться от 403; добавьте эти коды в часть исключения, когда вы получите исключение 403.

 val response = Http(your_url)
val responseExecute = response.execute()
val responseBody = responseExecute.body.toString
val xml = XML.loadString(responseBody)