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

Phoenix路由中Regex.match?/2触发FunctionClauseError问题求助

解决Phoenix路由中Regex.match?触发FunctionClauseError的问题

我来帮你搞定这个问题,你遇到的FunctionClauseError主要是几个细节没注意到,咱们一步步修正:

问题根源

  1. Elixir布尔值是小写的:你用了大写的True/False,这在Elixir里会被当作自定义原子,不是标准布尔值,直接导致逻辑判断完全出错。
  2. 未处理nil参数:当请求里缺少某个参数时,Map.get会返回nil,而Regex.match?/2要求第二个参数必须是字符串,传nil直接触发函数子句错误。
  3. 赋值与判断搞混:if error = True是赋值操作,不是相等判断,这会导致无论有没有错误都会进入错误分支。
  4. 键名格式错误:%{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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:56:19