Phoenix路由中Regex.match?/2触发FunctionClauseError问题求助
解决Phoenix路由中Regex.match?触发FunctionClauseError的问题
我来帮你搞定这个问题,你遇到的FunctionClauseError主要是几个细节没注意到,咱们一步步修正:
问题根源
- Elixir布尔值是小写的:你用了大写的
True/False,这在Elixir里会被当作自定义原子,不是标准布尔值,直接导致逻辑判断完全出错。 - 未处理
nil参数:当请求里缺少某个参数时,Map.get会返回nil,而Regex.match?/2要求第二个参数必须是字符串,传nil直接触发函数子句错误。 - 赋值与判断搞混:
if error = True是赋值操作,不是相等判断,这会导致无论有没有错误都会进入错误分支。 - 键名格式错误:
%{Reason => "..."}里的Reason是大写开头的原子,不符合Elixir命名规范,返回JSON时也会出现大写键,通常我们用小写的:reason更合理。
修正后的代码
def postServidor(conn, parameters) do reasons = [] error = false # 校验data_nascimento data_nascimento = Map.get(parameters, "data_nascimento") unless is_string(data_nascimento) and Regex.match?(~r/^(19[0-9]{2}|2[0-9]{3})-(0[1-9]|1[012])-([123]0|[012][1-9]|31)$/, data_nascimento) do reasons = reasons ++ [%{reason: "[data_nascimento] missing or failed to match API requirements. It should look like this: 1969-02-12"}] error = true end # 校验nome nome = Map.get(parameters, "nome") unless is_string(nome) and Regex.match?(~r/^([A-Z][a-z]+([ ]?[a-z]?['-]?[A-Z][a-z]+)*)$/, nome) do reasons = reasons ++ [%{reason: "[nome] missing or failed to match API requirements. It should look like this: Firstname Middlename(optional) Lastname"}] error = true end # 校验nome_identificacao nome_identificacao = Map.get(parameters, "nome_identificacao") unless is_string(nome_identificacao) and Regex.match?(~r/^([A-Z][a-z]+([ ]?[a-z]?['-]?[A-Z][a-z]+)*)$/, nome_identificacao) do reasons = reasons ++ [%{reason: "[nome_identificacao] missing or failed to match API requirements. It should look like this: Firstname Middlename(optional) Lastname"}] error = true end # 校验sexo sexo = Map.get(parameters, "sexo") unless is_string(sexo) and Regex.match?(~r/\b[MF]{1}\b/, sexo) do reasons = reasons ++ [%{reason: "[sexo] missing or failed to match API requirements. It should look like this: M for male, F for female"}] error = true end # 校验id_pessoa id_pessoa = Map.get(parameters, "id_pessoa") unless is_string(id_pessoa) and Regex.match?(~r/\b[0-9]+\b/, id_pessoa) do reasons = reasons ++ [%{reason: "[id_pessoa] missing or failed to match API requirements. It should be numeric."}] error = true end # 校验matricula_interna matricula_interna = Map.get(parameters, "matricula_interna") unless is_string(matricula_interna) and Regex.match?(~r/\b[0-9]+\b/, matricula_interna) do reasons = reasons ++ [%{reason: "[matricula_interna] missing or failed to match API requirements. It should be numeric."}] error = true end # 校验siape siape = Map.get(parameters, "siape") unless is_string(siape) and Regex.match?(~r/\b[0-9]+\b/, siape) do reasons = reasons ++ [%{reason: "[siape] missing or failed to match API requirements. It should be numeric."}] error = true end if error == true do conn |> put_status(400) |> json(reasons) else IO.puts("ok") # 补充正常响应,Phoenix路由必须返回conn conn |> json(%{status: "ok"}) end end
关键改动说明
- 把所有
True/False替换成Elixir标准的小写true/false - 每个校验前先通过
is_string/1检查参数是否存在且是字符串,避免传nil给Regex.match? - 把
if not ...改成更符合Elixir习惯的unless ...,逻辑更直观 - 修正错误分支的判断条件:用
error == true代替error = true,避免误赋值 - 把错误信息的键改成
:reason,返回JSON时会自动转成小写的"reason",符合API规范 - 补充了正常分支的响应(原来的
IO.puts仅在控制台打印,Phoenix路由必须返回conn对象)
内容的提问来源于stack exchange,提问作者Auyer
相关产品推荐
相关产品推荐

