Domino xAgent POST请求报500错误:$$viewid ID缺失
当使用XPage编写的xAgent处理POST请求时,若请求未携带$$viewid参数或Content-Type不是表单类(如multipart/form-data、application/x-www-form-urlencoded),会抛出CLFAD0384E: Page instance not found的500错误,GET请求正常,常规的viewState="nostate"等设置无法解决该问题。
解决方案
1. 使用Java Agent替代XPage xAgent
Java Agent直接基于Servlet API处理请求,不受XPage Faces框架的状态验证限制,支持任意Content-Type的POST请求:
import lotus.domino.*; import javax.servlet.http.*; public class CustomXAgent extends AgentBase { public void NotesMain() { try { HttpServletRequest request = (HttpServletRequest) getAgentContext().getRequest(); HttpServletResponse response = (HttpServletResponse) getAgentContext().getResponse(); // 设置响应头 response.setContentType("text/plain"); response.setHeader("Cache-Control", "no-cache"); // 处理请求并返回结果 response.getWriter().write(request.getMethod()); response.getWriter().flush(); response.getWriter().close(); } catch (Exception e) { e.printStackTrace(); } } }
编译后将该Agent部署到数据库,调用路径为/yourdb.nsf/CustomXAgent?OpenAgent,即可正常接收各类POST请求。
2. 改造XPage,强制跳过Faces状态验证
在XPage的beforePageLoad事件中直接接管请求处理,终止Faces生命周期,避免框架的参数检查:
<?xml version="1.0" encoding="UTF-8"?> <xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false" viewState="nostate"> <xp:this.beforePageLoad><![CDATA[#{javascript: var exCon = facesContext.getExternalContext(); var request = exCon.getRequest(); var response = exCon.getResponse(); // 直接处理请求 response.setContentType("text/plain"); response.setHeader("Cache-Control", "no-cache"); response.getWriter().write(request.getMethod()); response.getWriter().close(); // 终止Faces流程,避免后续验证 facesContext.responseComplete(); }]]></xp:this.beforePageLoad> </xp:view>
这种方式保留XPage形式,但完全绕过了Faces的状态验证逻辑,支持任意Content-Type的POST请求。
3. 配置Servlet过滤器自动添加$$viewid参数
如果必须保留原有XPage xAgent结构,可以通过Servlet过滤器为所有目标POST请求自动注入$$viewid参数:
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.HashMap; import java.util.Map; public class ViewIdInjectFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String requestURI = req.getRequestURI(); // 匹配你的xAgent路径 if (requestURI.endsWith("/yourXAgent.xsp") && "POST".equalsIgnoreCase(req.getMethod())) { // 包装请求,添加$$viewid参数 HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(req) { @Override public String getParameter(String name) { if ("$$viewid".equals(name)) { return "!!"; } return super.getParameter(name); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> paramMap = new HashMap<>(super.getParameterMap()); if (!paramMap.containsKey("$$viewid")) { paramMap.put("$$viewid", new String[]{"!!"}); } return paramMap; } }; chain.doFilter(wrappedRequest, response); } else { chain.doFilter(request, response); } } @Override public void destroy() {} }
在Domino服务器的web.xml中注册该过滤器,指定拦截路径为你的xAgent地址,即可让非表单类型的POST请求通过验证。
原因说明
XPage的Faces框架默认会验证POST请求中的$$viewid参数,用于关联页面实例;即使设置viewState="nostate",框架依然会执行该检查。而restService本质上还是依赖XPage的基础框架,因此同样受该限制。只有完全绕过Faces的状态验证逻辑,或自动注入所需参数,才能支持非表单类型的POST请求。
内容的提问来源于stack exchange,提问作者Adam

