Я новичок в Elixir / Phoenix и пытаюсь учиться, создавая небольшое приложение.

Я получаю данные из стороннего API и продолжаю получать следующую ошибку.

(ArgumentError) argument error :erlang.iolist_to_binary([%{"24h_volume" => "1000", "name" => "some_name"},{...}])

В моем контроллере есть:

HTTPoison.start

%HTTPoison.Response{body: body} = HTTPoison.get!(url)
body = body
       |> Poison.decode!(keys: :atoms!)

Это не работает. Я использовал (keys:: atom), что не рекомендуется в документации Poison.

Вот моя схема:

schema "things" do
  field :name, :string
  field :volume_24h, :float

  timestamps()
end

@doc false
def changeset(%Thing{} = thing, attrs) do
  thing
  |> cast(attrs, [:volume_24h, :name])
  |> validate_not_nil([:volume_24h, :name])
end

def validate_not_nil(changeset, fields) do
  Enum.reduce(fields, changeset, fn field, changeset ->
    if get_field(changeset, field) == nil do
      add_error(changeset, field, "nil")
    else
      changeset
    end
  end)
end

Я пытаюсь использовать другое имя поля для «24h_volume» и получаю такую ошибку:

(ArgumentError) argument error :erlang.binary_to_existing_atom("24h_volume", :utf8)

Мне здесь явно чего-то не хватает.

Есть ли способ передать желаемое имя поля в Poison, потому что "24h_volume" не будет допустимым атомом? Как я могу исправить эти ошибки?

1
alexts 31 Дек 2017 в 01:56

2 ответа

Лучший ответ

У вас беспорядок с параметром volume_24h.

Как указано в документации Poison:

Обратите внимание, что keys: :atoms! повторно использует существующие атомы, т.е. если :name не был выделен перед вызовом, вы получите сообщение об ошибке аргумента.

Именно это и происходит. Приложение ожидает, что ключ :volume_24h придет из запроса, но оно (по какой-то причине, возможно, из-за неправильной конфигурации формы подобного) получает 24h_volume. Используя разрешающий вызов atoms вместо atoms!, вы ничего не решили, вы скрыли проблему . На самом деле происходит то, что приходит ключ 24h_volume, и эффективно отбрасывается вызовом cast.

Вам нужно либо исправить друга / отправителя запроса на отправку ключа volume_24h, либо настроить контроллер, чтобы он принимал ключ :"24h_volume".


Есть две причины, по которым не рекомендуется использовать atoms. Один из них описан в документации Poison: так называемая "атака атомами DOS" возможна со случайными запросами, имеющими случайные ключи, которые выдаются впоследствии, переполняя хранилище атомов. Во-вторых, с помощью испорченной версии atoms! можно защитить себя от опечаток / неправильной конфигурации, подобных приведенной выше.

FWIW, атом для правильного ключа выделяется в определении схемы.

1
Aleksei Matiushkin 31 Дек 2017 в 06:43

Вы должны определить свой атом следующим образом, потому что ваш атом обычно незаконно начинать с числа, но вы можете обойти это, заключив его в "

Так что измените свой атом следующим образом:

:"24_volume"
2
Andrei Sfat 30 Дек 2017 в 23:08