使用Mechanize保存文件到SMB共享驱动器时触发401认证错误
直接保存文件到SMB共享卷时Mechanize频繁抛出401 NTLM认证错误
我已连接SMB共享卷,使用Ruby的Mechanize库从专有资产管理系统批量下载文件并直接保存到共享驱动器,代码示例如下:
agent = Mechanize.new agent.add_auth("http://website.com", username, password) agent.get(URL).save("/Volumes/shared_folder/file.pdf")
操作最初几次可成功执行,但后续每次都会抛出401错误:
/Users/m/.rvm/rubies/ruby-2.4.6/lib/ruby/gems/2.4.0/gems/mechanize-2.7.6/lib/mechanize/http/agent.rb:775:in `response_authenticate': 401 => Net::HTTPUnauthorized for [url] -- NTLM authentication failed -- available realms: (Mechanize::UnauthorizedError) from /Users/m/.rvm/rubies/ruby-2.4.6/lib/ruby/gems/2.4.0/gems/mechanize-2.7.6/lib/mechanize/http/agent.rb:323:in `fetch' from /Users/m/.rvm/rubies/ruby-2.4.6/lib/ruby/gems/2.4.0/gems/mechanize-2.7.6/lib/mechanize.rb:464:in `get'
如果将文件保存到脚本运行的本地工作目录,则不会出现任何错误。网站与共享驱动器的凭据不同,不确定是否与此相关。请问是否存在无需先保存到本地的解决办法?
补充说明:
添加如下rescue语句后脚本可完成执行,但每1-3次下载就会触发一次,整体方案较为繁琐:
rescue Mechanize::UnauthorizedError => e agent = Mechanize.new agent.add_auth("http://website.com", username, password) retry
我还尝试设置agent.read_timeout,但无法确定每次迭代的具体耗时,因此无法设置合理值。
可行解决思路
复用Mechanize实例并重置认证
无需每次出错都重建实例,只需重置当前实例的认证信息,减少状态初始化带来的问题:agent = Mechanize.new agent.add_auth("http://website.com", username, password) download_urls.each do |url, save_path| begin agent.get(url).save(save_path) rescue Mechanize::UnauthorizedError => e # 重置认证而非重建实例 agent.auth("http://website.com", username, password) retry end end禁用认证缓存
Mechanize的NTLM认证缓存可能在跨文件系统写入时失效,强制每次请求重新验证:agent = Mechanize.new # 关闭认证缓存 agent.http.cache_store = nil agent.add_auth("http://website.com", username, password)分离网络请求与文件写入
先将文件内容读取到内存,再写入SMB卷,避免IO延迟导致认证会话超时:agent = Mechanize.new agent.add_auth("http://website.com", username, password) download_urls.each do |url, save_path| begin # 先获取响应到内存 response = agent.get(url) # 再写入共享卷 File.open(save_path, 'wb') { |f| f.write(response.body) } rescue Mechanize::UnauthorizedError => e agent.auth("http://website.com", username, password) retry end end优化SMB挂载参数
SMB卷的写入延迟可能阻塞请求线程,导致服务器端会话超时。比如在macOS上挂载时可添加-o nobrowse或调整缓存大小,提升IO性能。
内容的提问来源于stack exchange,提问作者lumos
相关产品推荐
相关产品推荐

