HTTP

从互联网其他位置获取信息往往很有帮助。

例如,假设我们希望加载沃尔特·李普曼的《公众舆论》的全文。这本书于 1922 年出版,从历史角度阐述了大众媒体的兴起及其对民主的影响。在此,我们将重点介绍如何使用 elm/http 包将这本书载入到我们的程序中!

点击蓝色的“编辑”按钮,即可在线编辑器中查看此程序。在完全显示这本书之前,您可能会在屏幕上看到“加载中...”这一提示。立即点击蓝色按钮!

import Browser
import Html exposing (Html, text, pre)
import Http



-- MAIN


main =
  Browser.element
    { init = init
    , update = update
    , subscriptions = subscriptions
    , view = view
    }



-- MODEL


type Model
  = Failure
  | Loading
  | Success String


init : () -> (Model, Cmd Msg)
init _ =
  ( Loading
  , Http.get
      { url = "https://elm-lang.org/assets/public-opinion.txt"
      , expect = Http.expectString GotText
      }
  )



-- UPDATE


type Msg
  = GotText (Result Http.Error String)


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GotText result ->
      case result of
        Ok fullText ->
          (Success fullText, Cmd.none)

        Err _ ->
          (Failure, Cmd.none)



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.none



-- VIEW


view : Model -> Html Msg
view model =
  case model of
    Failure ->
      text "I was unable to load your book."

    Loading ->
      text "Loading..."

    Success fullText ->
      pre [] [ text fullText ]

此部分的一些内容应该让人熟悉,因为它们来自 Elm 架构先前的示例。我们仍然有应用程序的 Model。我们仍然有一个对消息做出反应的 update。我们仍然有一个在屏幕上显示所有内容的 view 函数。

新部分通过 initupdate 中的一些更改,以及 subscription 的添加,扩展了我们之前看到的核心模式。

init

init 函数描述如何初始化我们的程序

init : () -> (Model, Cmd Msg)
init _ =
  ( Loading
  , Http.get
      { url = "https://elm-lang.org/assets/public-opinion.txt"
      , expect = Http.expectString GotText
      }
  )

我们始终必须生成初始 Model,但现在我们还会生成我们希望立即执行的某个操作的 命令。该命令将最终生成一个输入到 update 函数的 Msg

我们的书籍网站从 Loading 状态启动,我们希望获取我们书籍的全文。在使用 Http.get 执行 GET 请求时,我们指定要获取数据的 url,并且指定我们 expect 该数据是什么。因此,在我们的案例中,url 指向 Elm 网站上的某些数据,并且我们expect 该数据是我们可以显示在屏幕上的一大串 String

Http.expectString GotText 行表示的不仅仅是我们expect 一个String。它还表示当我们收到响应时,它应转换为GotText消息

type Msg
  = GotText (Result Http.Error String)

-- GotText (Ok "The Project Gutenberg EBook of ...")
-- GotText (Err Http.NetworkError)
-- GotText (Err (Http.BadStatus 404))

请注意,我们正在使用几节前的Result类型。这使我们能够充分考虑update函数中的可能失败。说到update函数...

注意:如果您想知道为什么init是一个函数(以及我们为什么忽略参数),我们将在即将到来的 JavaScript 交互操作章节中讨论它!(预览:该参数允许我们在初始化时从 JS 中获取信息。)

update

我们的update函数也返回了更多信息

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GotText result ->
      case result of
        Ok fullText ->
          (Success fullText, Cmd.none)

        Err _ ->
          (Failure, Cmd.none)

查看类型签名,我们看到我们不仅仅返回一个更新的模型。我们生成了一个命令,告诉 Elm 要做什么。

继续实现,我们像往常一样对消息进行模式匹配。收到GotText消息时,我们检查 HTTP 请求的Result,并根据请求是成功还是失败来更新模型。新部分是我们还提供了一个命令。

因此,如果我们成功获取了全文,我们说Cmd.none表示没有更多工作要做。我们已经得到了全文!

如果出现错误,我们也会说Cmd.none并且放弃。这本书的文字没有加载。如果我们要更花哨一些,我们可以对 Http.Error 进行模式匹配,并在超时或其他情况下重试请求。

这里的意思是,无论我们如何决定更新我们的模型,我们都可以自由地发出新的命令。我需要更多数据!我想要一个随机数!等

subscription

这个程序中另一个新东西是subscription函数。它允许你查看Model并决定你想订阅哪些信息。在我们的示例中,我们说Sub.none表示我们不需要订阅任何内容,但我们很快就会看到一个想要订阅当前时间的时钟示例!

摘要

当我们使用Browser.element创建程序时,我们会设置这样的系统

我们能够从initupdate发出命令。这允许我们随时做一些事情,比如发出 HTTP 请求。我们还可以订阅有趣的信息。(我们稍后会看到订阅的示例!)

个匹配 "" 的结果

    没有匹配 "" 的结果