如何在Play 2.3.x(Scala)中覆盖urlFormEncoded
解析器以使用另一个字符集?
我正在使用Scala中的Play framework 2.3.x编写适用于日语环境的BBS软件。
问题在于charset:客户端POST请求使用url编码(又名。"百分比编码")表单参数编码在Shift-JIS
- 日本着名的字符集 - 但Play将其解码为UTF-8
。这是可以预测的,因为它在https://github.com/playframework/playframework/blob/2.3.x/framework/src/play/src/main/scala/play/api/mvc/ContentTypes.scala#L515中是硬编码的。
我无法修改BBS客户端'编码,因为它是事实上的标准。
因此,我必须在Play中重写或覆盖url编码解码器以使用Shift_JIS
。
可能有一些解决方案:
Shift_JIS
,然后将正文重新编码为UTF-8
。play.api.mvc.BodyParsers.parse
并使用它的自定义解析器。我认为最有希望的选择是3,但我无法创建扩展object
的{{1}}。
那么,我怎样才能覆盖默认解析器并使用它(或者还有其他更好的解决方案)?
感谢。
答案 0 :(得分:0)
默认解析器使用RequestHeader的charset
(如果可用)。 charset
由Content-Type
标题确定。所以我假设客户端没有设置Content-Type
标题。
一种方法是通过包装RequestHeader来更改charset
。
定义包装器。
class WrappedRequestHeader(rh: RequestHeader) extends RequestHeader {
override def id = rh.id
override def secure = rh.secure
override def uri = rh.uri
override def remoteAddress = rh.remoteAddress
override def queryString = rh.queryString
override def method = rh.method
override def headers = rh.headers
override def path = rh.path
override def version = rh.version
override def tags = rh.tags
}
定义一个请求标头,如果原始标头没有它,则返回一个常量charset
。
class DefaultCharsetRequestHeader(rh: RequestHeader, defaultCharset: String) extends WrappedRequestHeader(rh) {
override lazy val charset = rh.charset orElse Some(defaultCharset) // Or always use Some(defaultCharset) if you want
}
然后,您可以从任何默认解析器创建BodyParser。
def createParser[A](parser: BodyParser[A], defaultCharset: String): BodyParser[A] = BodyParser[A] { rh =>
parser(new DefaultCharsetRequestHeader(rh, defaultCharset))
}
如果您想广泛应用它,也可以创建过滤器。
class DefaultCharsetFilter(defaultCharset: String) extends Filter {
override def apply(f: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] =
f(new DefaultCharsetRequestHeader(rh, defaultCharset))
}
我还没有试过上面的代码,但我希望它有效。
答案 1 :(得分:0)
我使用apache httpcomponents解决了此问题的续订请求。
我们可以将URL编码数据检索为原始文本,将parse.torelantText
指定为主体解析器。然后手动将URL编码数据解析为Map[String, Seq[String]]
并重新创建Request
。
我在下面显示代码。
在build.sbt
中定义依赖关系:
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.4"
定义要将Request[String]
转换为Request[Map[String, Seq[String]]]
的对象:
import play.api.mvc.{ Headers, Request }
object PercentEncoding {
import java.net.URI
import scala.collection.JavaConversions._
import org.apache.http.client.utils.URLEncodedUtils
import org.apache.http.NameValuePair
def extractSJISRequest(request: Request[String]) = {
val body = request.body
val parsed: Seq[NameValuePair] = URLEncodedUtils.parse(new URI("http://example.com/?" + body), "Shift_JIS")
val newBody = parsed.map { pair ⇒ (pair.getName, Seq(pair.getValue)) }.toMap
new Request[Map[String, Seq[String]]] {
override def body: Map[String, Seq[String]] = newBody
override def uri: String = request.uri
override def remoteAddress: String = request.remoteAddress
override def queryString: Map[String, Seq[String]] = request.queryString
override def method: String = request.method
override def headers: Headers = request.headers
override def path: String = request.path
override def version: String = request.version
override def tags: Map[String, String] = request.tags
override def id: Long = request.id
}
}
}
然后使用request
转换原始PercentEncoding
并定义隐式请求值而不是原始request
:
def hogehoge = Action(parse.tolerantText) { request ⇒
implicit val newRequest = PercentEncoding.extractSJISRequest(request)
...
}
它有效。