Scala调用Mediawiki API登录失败的原因排查
我用Scala写了一段调用MediaWiki API登录的代码,当前使用的MediaWiki版本是1.39.6,代码如下:
def login(botUN: String, botPW: String): Option[String] = { try { val s = requests.Session(verifySslCerts = false) val params0 = Map("action" -> "query", "meta" -> "tokens", "type" -> "login", "format" -> "json") val resp0 = s.get(MediawikiClient.wikiApi, params = params0) val loginToken = ujson.read(resp0)("query")("tokens")("logintoken").str val params1 = Map( "action" -> "login", "lgname" -> botUN, "lgpassword" -> botPW, "lgtoken" -> loginToken, "format" -> "json") val resp1 = s.post(MediawikiClient.wikiApi, data = params1) val result = ujson.read(resp1)("login")("result").str println(ujson.read(resp1)("login")("reason")) Some(result) } catch { case e: java.util.NoSuchElementException => None case e: requests.RequestFailedException => None } }
这段代码返回Some(Failed),控制台打印错误原因:Unable to continue login. Your session most likely timed out.
但使用相同的API地址和机器人账号凭据,运行MediaWiki官方提供的Python登录脚本(给所有HTTP请求加上verify = False参数)却能成功登录,返回结果类似:{'result': 'Success', 'lguserid': 123, 'lgusername': 'botname'}
我已经开启了Python脚本的完整调试日志,对比后没发现Scala请求有遗漏的操作;也尝试过手动处理Cookie、对齐Python脚本的请求头,但问题依然存在。现在需要找出Scala代码登录失败的原因,并解决这个问题。
可能的原因与解决办法
1. 请求参数编码与Content-Type问题
Python的requests.post默认会把data参数编码为application/x-www-form-urlencoded,但Scala的requests库可能未正确设置Content-Type头,或者参数提交格式不符合MediaWiki API要求。
- 解决办法:手动指定POST请求的Content-Type为
application/x-www-form-urlencoded,修改POST请求代码:
val resp1 = s.post( MediawikiClient.wikiApi, data = params1, headers = Map("Content-Type" -> "application/x-www-form-urlencoded") )
2. Session Cookie传递异常
MediaWiki登录流程依赖Session Cookie的正确传递,Scala的requests.Session可能未自动保存或传递第一个GET请求返回的Cookie,导致会话中断。
- 解决办法:手动提取并携带Cookie。在获取
resp0后,提取Cookie并在POST请求中携带:
// 提取第一个请求的Cookie val cookies = resp0.cookies.map(c => c.name -> c.value).toMap // POST请求时主动携带Cookie val resp1 = s.post( MediawikiClient.wikiApi, data = params1, cookies = cookies )
也可以检查requests.Session的文档,确认其自动管理Cookie的机制是否正常工作。
3. 登录Token提取错误
可能因为JSON解析路径错误,导致提取的loginToken无效,或者MediaWiki返回的Token格式有变化。
- 解决办法:打印第一个请求的完整响应内容,确认Token的位置和值:
println("First response: " + resp0.text)
检查logintoken是否正确提取,再对比POST请求中lgtoken参数的值是否一致。
4. User-Agent头差异
MediaWiki服务器可能对不同的User-Agent做了限制,Python的requests有默认的User-Agent,而Scala的requests库可能未设置,导致请求被识别为异常。
- 解决办法:设置与Python脚本一致的User-Agent头,比如:
val s = requests.Session( verifySslCerts = false, headers = Map("User-Agent" -> "python-requests/2.31.0") )
内容的提问来源于stack exchange,提问作者austbestos

