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