You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solr 8.9.0云模式开启Basic Authentication后索引遇IOException

问题描述
  • 环境:Solr 8.9.0 云模式,2个分片,通过security.json开启Basic Authentication(未启用授权模块)
  • security.json配置:
{  
  "authentication":{    
    "blockUnknown": true,    
    "class":"solr.BasicAuthPlugin",    
    "credentials":{"solr":"Y6xFaUPypZOWNmgaU+IkZ8eP4TJxXW50= bWtoYjk2Yjhscmx6a2Jveg=="},    
    "realm":"My Solr users",    
    "forwardCredentials": false  
  }
}
  • 上传至ZooKeeper的命令:
solr zk cp file:D:\Asite_work\Solr_8.9.0\shard1\bin\security.json zk:/security.json -z "localhost:12181,localhost:12182"
  • 现象:Web访问http://localhost:8983/solr可正常登录并使用,但通过代码索引时抛出错误:
org.apache.solr.client.solrj.impl.CloudSolrClient$RouteException: IOException occurred when talking to server at: http://localhost:8983/solr/documents_shard1_replica_n1
  • 索引代码:
final List<String> zkServers = new ArrayList<>();
zkServers.add("localhost:12181");
zkServers.add("localhost:12182");
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("solr", "Abc@123");
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
CloudSolrClient sc = new CloudSolrClient.Builder(zkServers, Optional.empty()).withParallelUpdates(true).withHttpClient(client).build();
sc.setDefaultCollection("documents");
sc.connect();
UpdateResponse resp = sc.add(docs, SolrConstants.COMMIT_WITHIN);

请问该错误产生的原因是什么?是否需要在ZooKeeper中进行额外配置?

问题分析与解决

错误原因

你的代码中配置的HttpClient默认采用挑战-响应模式的Basic认证:即先发送不带凭据的请求,等待Solr节点返回401未授权响应后,再提交认证凭据。但在Solr云模式下,CloudSolrClient会直接与分片副本通信,加上你开启了blockUnknown: true(拒绝未认证请求),未携带凭据的初始请求会被Solr直接拦截,从而抛出IO异常。

解决方法

修改HttpClient配置,添加预emptive(先发制人)认证拦截器,确保请求一开始就携带Basic Auth凭据。修改后的代码如下:

final List<String> zkServers = new ArrayList<>();
zkServers.add("localhost:12181");
zkServers.add("localhost:12182");

CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("solr", "Abc@123");
provider.setCredentials(AuthScope.ANY, credentials);

// 配置预emptive认证缓存
AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuthScheme = new BasicScheme();
// 针对Solr节点地址添加缓存,若有多个节点需逐一添加或使用通配符处理
authCache.put(new HttpHost("localhost", 8983, "http"), basicAuthScheme);

// 创建带预emptive认证的HttpClient
HttpClient client = HttpClientBuilder.create()
        .setDefaultCredentialsProvider(provider)
        .setDefaultAuthCache(authCache)
        .addInterceptorFirst(new PreemptiveAuthInterceptor())
        .build();

// 自定义预emptive认证拦截器
static class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
    @Override
    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
        AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
        // 若未设置认证方案,主动添加Basic认证
        if (authState.getAuthScheme() == null) {
            CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER);
            HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
            Credentials creds = credsProvider.getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
            if (creds != null) {
                authState.update(new BasicScheme(), creds);
            }
        }
    }
}

CloudSolrClient sc = new CloudSolrClient.Builder(zkServers, Optional.empty())
        .withParallelUpdates(true)
        .withHttpClient(client)
        .build();
sc.setDefaultCollection("documents");
sc.connect();
UpdateResponse resp = sc.add(docs, SolrConstants.COMMIT_WITHIN);

额外说明

不需要在ZooKeeper中进行额外配置,当前的security.json认证配置已经生效,问题完全出在客户端请求的认证方式上。

内容的提问来源于stack exchange,提问作者vishal patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 05:30:14