如何使用 spray-client 设置 non-standard User-Agent?
How do I set a non-standard User-Agent using spray-client?
我正在使用 Scala 和 Akka 为电信公司构建应用程序,需要使用 UCIP protocol 与帐户信息和充值服务器进行通信。
UCIP 是一个简单的协议,建立在 XMLRPC 之上;我遇到的唯一问题是它要求客户以特定格式 User-Agent: <client name>/<protocol version>/<client version>
设置 User-Agent
header,喷雾解析为无效。
我尝试创建自定义 User-Agent
header,继承自 spray.http.HttpHeader
,但它仍然不起作用。到目前为止,这是我得到的:
import akka.actor.ActorSystem
import akka.event.{Logging, LoggingAdapter}
import spray.client.pipelining._
import spray.http._
import spray.httpx._
case class `User-Agent`(value: String) extends HttpHeader {
def lowercaseName: String = "user-agent"
def name: String = "User-Agent"
def render[R <: Rendering](r: R): r.type = r ~~ s"User-Agent: $value"
}
class UcipClient(val url: String, val protocol: String, username: String, password: String) (implicit system: ActorSystem) {
val log = Logging.getLogger(system, this)
val logRequest: HttpRequest => HttpRequest = { r => log.debug(r.toString); r }
val logResponse: HttpResponse => HttpResponse = { r => log.debug(r.toString); r }
val pipeline = (
addHeader(`User-Agent`("USSD-UCIP/%s/1.0".format(protocol)))
~> addCredentials(BasicHttpCredentials(username, password))
~> logRequest
~> sendReceive
~> logResponse
)
def send(req: UcipRequest) = pipeline(Post(url, req.getRequest))
}
我的请求保持 returning "Sorry, Error occured: 403, Invalid protocol version Not defined",但是,当我使用 curl
.
发送相同的详细信息时,它们 return 是正确的响应
我错过了什么,这甚至可以用 spray-client 实现吗?我花了相当多的时间检查互联网(这让我走向了自定义 header 路线),但仍然没有弄明白......非常感谢任何帮助:-)
原来我离答案不远了。在检查通过网络发送的 header 时,我注意到 User-Agent
被设置了两次:一次是我的代码,另一次是 Spray(因为它认为我的 header 无效)。
将 spray.can.client.user-agent-header
设置为空字符串 ""
删除了第二个 header,请求成功。这是自定义 header:
的最终版本
import spray.http._
object CustomHttpHeaders {
case class `User-Agent`(val value: String) extends HttpHeader with Product with Serializable {
def lowercaseName: String = "user-agent"
def name: String = "User-Agent"
def render[R <: Rendering](r: R): r.type = r ~~ s"User-Agent: $value"
}
}
最后的 UCIP 客户端:
import akka.actor.ActorRefFactory
import com.typesafe.config.Config
import scala.concurrent.ExecutionContext.Implicits.global
import scala.xml.NodeSeq
import spray.client.pipelining._
import spray.http._
import spray.httpx._
class UcipFault(val code: Int, msg: String) extends RuntimeException(s"$code: $msg")
class AirException(val code: Int) extends RuntimeException(s"$code")
class UcipClient(config: Config, val url: String)(implicit context: ActorRefFactory) {
import CustomHttpHeaders._
val throwOnFailure: NodeSeq => NodeSeq = {
case f if (f \ "fault").size != 0 =>
val faultData = (f \ "fault" \ "member" \ "value")
throw new UcipFault((faultData \ "i4").text.toInt,
(faultData \ "string").text)
case el =>
val responseCode = ((el \ "member")
.filter { n => (n \ "name").text == "responseCode" }
.map { n => (n \ "i4").text.toInt }).head
if (responseCode == 0) el else throw new AirException(responseCode)
}
val pipeline = (
addHeader(`User-Agent`("USSD-UCIP/%s/1.0".format(config.getString("ucip.server-protocol"))))
~> addCredentials(BasicHttpCredentials(config.getString("ucip.server-username"), config.getString("ucip.server-password")))
~> sendReceive
~> unmarshal[NodeSeq]
~> throwOnFailure
)
def send(req: UcipRequest) = pipeline(Post(url, req.getRequest))
}
我正在使用 Scala 和 Akka 为电信公司构建应用程序,需要使用 UCIP protocol 与帐户信息和充值服务器进行通信。
UCIP 是一个简单的协议,建立在 XMLRPC 之上;我遇到的唯一问题是它要求客户以特定格式 User-Agent: <client name>/<protocol version>/<client version>
设置 User-Agent
header,喷雾解析为无效。
我尝试创建自定义 User-Agent
header,继承自 spray.http.HttpHeader
,但它仍然不起作用。到目前为止,这是我得到的:
import akka.actor.ActorSystem
import akka.event.{Logging, LoggingAdapter}
import spray.client.pipelining._
import spray.http._
import spray.httpx._
case class `User-Agent`(value: String) extends HttpHeader {
def lowercaseName: String = "user-agent"
def name: String = "User-Agent"
def render[R <: Rendering](r: R): r.type = r ~~ s"User-Agent: $value"
}
class UcipClient(val url: String, val protocol: String, username: String, password: String) (implicit system: ActorSystem) {
val log = Logging.getLogger(system, this)
val logRequest: HttpRequest => HttpRequest = { r => log.debug(r.toString); r }
val logResponse: HttpResponse => HttpResponse = { r => log.debug(r.toString); r }
val pipeline = (
addHeader(`User-Agent`("USSD-UCIP/%s/1.0".format(protocol)))
~> addCredentials(BasicHttpCredentials(username, password))
~> logRequest
~> sendReceive
~> logResponse
)
def send(req: UcipRequest) = pipeline(Post(url, req.getRequest))
}
我的请求保持 returning "Sorry, Error occured: 403, Invalid protocol version Not defined",但是,当我使用 curl
.
我错过了什么,这甚至可以用 spray-client 实现吗?我花了相当多的时间检查互联网(这让我走向了自定义 header 路线),但仍然没有弄明白......非常感谢任何帮助:-)
原来我离答案不远了。在检查通过网络发送的 header 时,我注意到 User-Agent
被设置了两次:一次是我的代码,另一次是 Spray(因为它认为我的 header 无效)。
将 spray.can.client.user-agent-header
设置为空字符串 ""
删除了第二个 header,请求成功。这是自定义 header:
import spray.http._
object CustomHttpHeaders {
case class `User-Agent`(val value: String) extends HttpHeader with Product with Serializable {
def lowercaseName: String = "user-agent"
def name: String = "User-Agent"
def render[R <: Rendering](r: R): r.type = r ~~ s"User-Agent: $value"
}
}
最后的 UCIP 客户端:
import akka.actor.ActorRefFactory
import com.typesafe.config.Config
import scala.concurrent.ExecutionContext.Implicits.global
import scala.xml.NodeSeq
import spray.client.pipelining._
import spray.http._
import spray.httpx._
class UcipFault(val code: Int, msg: String) extends RuntimeException(s"$code: $msg")
class AirException(val code: Int) extends RuntimeException(s"$code")
class UcipClient(config: Config, val url: String)(implicit context: ActorRefFactory) {
import CustomHttpHeaders._
val throwOnFailure: NodeSeq => NodeSeq = {
case f if (f \ "fault").size != 0 =>
val faultData = (f \ "fault" \ "member" \ "value")
throw new UcipFault((faultData \ "i4").text.toInt,
(faultData \ "string").text)
case el =>
val responseCode = ((el \ "member")
.filter { n => (n \ "name").text == "responseCode" }
.map { n => (n \ "i4").text.toInt }).head
if (responseCode == 0) el else throw new AirException(responseCode)
}
val pipeline = (
addHeader(`User-Agent`("USSD-UCIP/%s/1.0".format(config.getString("ucip.server-protocol"))))
~> addCredentials(BasicHttpCredentials(config.getString("ucip.server-username"), config.getString("ucip.server-password")))
~> sendReceive
~> unmarshal[NodeSeq]
~> throwOnFailure
)
def send(req: UcipRequest) = pipeline(Post(url, req.getRequest))
}