CherryPy中_cp_dispatch无法将batch/路由至realbatch方法的问题
CherryPy _cp_dispatch 路由问题解决
问题背景
我用CherryPy实现了一个处理REST API的对象,但无法正确使用_cp_dispatch完成路由映射:
- 期望将
batch/路由到realbatch()方法,但当前配置下该方法未被调用 - 期望将
batch/{id}/product/{sku}路由到product()方法,这部分目前正常 - 若将
realbatch重命名为index,虽然能解决batch/的路由问题,但会错误匹配类似batc/的无效路径 - 最终目标:仅匹配指定的合法路径,其他所有路径返回404
当前代码
import cherrypy class Products(object): def __init__(self, product_database): self.product_database = product_database def _cp_dispatch(self, vpath): # batch/ if len(vpath) == 1 and vpath[0] == "batch": vpath[0] = "realbatch" return self # batch/{id}/product/ if len(vpath) == 3 and vpath[0] == "batch": vpath.pop(0) # pop "batch" cherrypy.request.params['batch_id'] = vpath.pop(0) return self # batch/{id}/product/{sku}/ if len(vpath) == 4 and vpath[0] == "batch" and vpath[2] == "product": vpath.pop(0) # pop "batch" cherrypy.request.params['batch_id'] = vpath.pop(0) vpath.pop(0) # pop "product" cherrypy.request.params['sku'] = vpath[0] vpath[0] = "product" return self # defaults return self # POST rest-products/batch --> create a batch (name in JSON body), return batch id # GET rest-products/batch --> return list of batches @cherrypy.expose @cherrypy.tools.json_out() def realbatch(self): # this method is not called when calling "batch/" pass # POST rest-products/batch/{id}/product --> add product to batch (product data in JSON body) @cherrypy.expose @cherrypy.tools.json_out() def product(self, batch_id, sku = None): # this method is called when calling "batch/{id}/product/" or "batch/{id}/product/{sku}" pass
问题分析
你对_cp_dispatch的调用时机理解有误:CherryPy不会在方法匹配失败后才调用它,而是在尝试匹配任何方法之前就执行_cp_dispatch来修改路径。当前代码的核心问题是:
- 默认返回
self会让CherryPy继续尝试匹配当前对象的其他方法(如index),导致无效路径被错误处理 batch/的路径修改逻辑本身是正确的,但需要确保后续路径匹配时能精准找到realbatch方法
修正方案
调整后的_cp_dispatch实现
import cherrypy class Products(object): def __init__(self, product_database): self.product_database = product_database def _cp_dispatch(self, vpath): # 精确匹配 batch/ if len(vpath) == 1 and vpath[0] == "batch": vpath[0] = "realbatch" return self # 精确匹配 batch/{id}/product/ if len(vpath) == 3 and vpath[0] == "batch" and vpath[2] == "product": vpath.pop(0) # 移除"batch" cherrypy.request.params['batch_id'] = vpath.pop(0) # 提取batch_id return self # 精确匹配 batch/{id}/product/{sku}/ if len(vpath) == 4 and vpath[0] == "batch" and vpath[2] == "product": vpath.pop(0) # 移除"batch" cherrypy.request.params['batch_id'] = vpath.pop(0) # 提取batch_id vpath.pop(0) # 移除"product" cherrypy.request.params['sku'] = vpath.pop(0) # 提取sku vpath.insert(0, "product") # 重置路径为["product"],匹配product方法 return self # 不匹配的路径返回None,直接触发404 return None @cherrypy.expose @cherrypy.tools.json_out() def realbatch(self): # 现在访问batch/会正确调用此方法 if cherrypy.request.method == "GET": # 返回批次列表逻辑 return self.product_database.get_batches() elif cherrypy.request.method == "POST": # 创建批次逻辑 batch_data = cherrypy.request.json batch_id = self.product_database.create_batch(batch_data["name"]) return {"batch_id": batch_id} @cherrypy.expose @cherrypy.tools.json_out() def product(self, batch_id, sku = None): if cherrypy.request.method == "POST": # 向批次添加产品逻辑 product_data = cherrypy.request.json self.product_database.add_product_to_batch(batch_id, product_data) return {"status": "success"} elif cherrypy.request.method == "GET" and sku: # 获取指定批次下的指定产品逻辑 product = self.product_database.get_product_in_batch(batch_id, sku) return product
关键修改点
- 精确路径匹配:为
batch/{id}/product/的匹配增加了vpath[2] == "product"条件,避免误匹配其他类似结构的路径 - 无效路径返回404:默认分支返回
None,而不是self,CherryPy会直接返回404状态码,不会尝试匹配其他方法 - 明确路径重置逻辑:在处理
batch/{id}/product/{sku}/时,确保修改后的vpath精准指向product方法 - 补充方法内部的请求逻辑:完善了
realbatch和product方法的HTTP请求处理示例,让代码更完整
内容的提问来源于stack exchange,提问作者Bart Friederichs
相关产品推荐
相关产品推荐

