LDAP分页搜索结果异常:仅返回单页数据且无响应控件
分析LDAP分页查询仅返回单页数据及控制台提示"No controls were sent from the server"的问题
你遇到的这两个核心问题其实是同一个逻辑错误导致的——分页控制的处理位置完全错了,咱们来一步步捋清楚:
核心问题1:为什么只返回单页数据?
你把获取分页响应控制、重置分页请求控制的代码,放到了遍历单条用户结果的while (answer.hasMoreElements())循环里面。这意味着你刚处理完当前页的第一个用户,就去更新了分页cookie和请求控制,直接干扰了当前页剩余结果的遍历流程,导致程序只能拿到当前页的所有数据后就终止,无法触发下一页的查询。
正确的逻辑应该是:先把当前页的所有用户结果完整遍历并处理完,再去处理分页响应、更新cookie、准备下一页的查询。
核心问题2:为什么每条用户记录都输出"No controls were sent from the server"?
LDAP服务器的分页响应控制(PagedResultsResponseControl)是在整个当前页的所有结果都返回完毕后才会发送给客户端的,而不是每返回一个用户就发一次。你在遍历每个用户时都调用ctx.getResponseControls(),这时候服务器还没返回分页控制,自然拿不到目标控制,就会输出那句提示。
修复后的代码片段
把分页相关的处理逻辑从用户遍历的while循环里移出来,放到do-while循环的末尾,也就是当前页结果全部处理完之后:
public void stupidSearch(String searchOptions) { String tempString = ""; try { LdapContext ctx = new InitialLdapContext(env, null); // Activate paged results int pageSize = 20; byte[] cookie = null; ctx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)}); int total; // 注意:补充初始化SearchControls,原代码遗漏了这一步 SearchControls searchCtls = new SearchControls(); // Specify the attributes to return String returnedAtts[] = {"Name", "samAccountName", "mail", "UserAccountControl", "distinguishedName"}; searchCtls.setReturningAttributes(returnedAtts); // Specify the search scope searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); // 省略searchFilter和searchBase的赋值逻辑(与原代码一致) String searchFilter = ""; String searchBase = ""; // ...(这里保留你原有的searchFilter和searchBase的判断逻辑) do { System.out.println(searchBase); // Search for objects using the filter NamingEnumeration<SearchResult> answer = ctx.search(searchBase, searchFilter, searchCtls); // Loop through the current page's search results while (answer.hasMoreElements()) { SearchResult sr = (SearchResult) answer.next(); Attributes attrs = sr.getAttributes(); // 保留你原有的用户属性处理逻辑 tempString = attrs.get("distinguishedName").toString(); tempString = tempString.substring(tempString.indexOf(",")+4); tempString = tempString.substring(0, tempString.indexOf(",DC=")); String[] reverseString = tempString.split(",OU="); List<String> reverseList = Arrays.asList(reverseString); Collections.reverse(reverseList); tempString = ""; for (String reverseString1: reverseString) { tempString = tempString + "\\" + reverseString1; } tempString = tempString.substring(1); // 假设location是类成员变量 location.add(tempString); String enableCheck = attrs.get("UserAccountControl").toString().replaceAll(".*: ", ""); String isEnabled = isActive(enableCheck).toString(); // 假设results1-4是类成员变量 results1.add(attrs.get("Name").toString()); results2.add(attrs.get("samAccountName").toString()); results4.add(isEnabled); results3.add(attrs.get("mail") != null ? attrs.get("mail").toString() : ""); } // 当前页结果处理完毕,再处理分页响应 Control[] controls = ctx.getResponseControls(); cookie = null; if (controls != null) { for (Control control : controls) { if (control instanceof PagedResultsResponseControl) { PagedResultsResponseControl prrc = (PagedResultsResponseControl) control; total = prrc.getResultSize(); if (total != 0) { System.out.println("***************** END-OF-PAGE " + "(total : " + total + ") *****************\n"); } else { System.out.println("***************** END-OF-PAGE " + "(total: unknown) ***************\n"); } cookie = prrc.getCookie(); } } } else { System.out.println("No controls were sent from the server"); } // 准备下一页的分页请求 if (cookie != null && cookie.length != 0) { ctx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)}); } } while (cookie != null && cookie.length != 0); // 避免空cookie导致的无限循环 ctx.close(); } catch (NamingException e) { System.out.println("Search error: " + e); System.exit(-1); } catch (IOException ex) { Logger.getLogger(ADData.class.getName()).log(Level.SEVERE, null, ex); } }
额外注意事项
- 补充了
SearchControls的初始化代码,原代码遗漏这一步会触发空指针异常 - 调整了循环终止条件,判断
cookie != null && cookie.length != 0,避免部分LDAP服务器返回空cookie数组导致的无限循环 - 修复了原代码中位于catch块外的日志语句,避免编译错误
内容的提问来源于stack exchange,提问作者acidrain
相关产品推荐
相关产品推荐

