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

Elm对接Django时如何自动将CSRF Token添加至HTTP请求头?

解决方案

Elm官方的Http库没有提供类似Axios的全局默认配置能力,无法声明式全局自动注入请求头,但是可以通过两层封装实现相同的使用体验,无需每次编写请求时手动处理CSRF token。

第一步:获取CSRF Token

Elm运行环境无法直接读取浏览器Cookie,有两种稳定的获取CSRF Token的方案:

  • 方案1:Django模板注入到Elm启动参数(Flags)
    在Django渲染的入口HTML页面中,直接将CSRF Token通过初始化参数传给Elm:
    <script>
    // 从Django模板获取csrf token,传入Elm
    const app = Elm.Main.init({
      flags: {
        csrfToken: "{{ csrf_token }}"
      }
    })
    </script>
    Elm侧对应定义Flags类型,将拿到的token存在全局Model中即可。
    
  • 方案2:通过端口从JS侧读取Cookie
    如果Elm应用是纯静态部署、不通过Django模板渲染,可以定义Elm端口,在JS侧读取Cookie中的csrftoken值传给Elm:
    // JS侧读取Cookie的csrftoken
    function getCsrfToken() {
      const value = `; ${document.cookie}`;
      const parts = value.split(`; csrftoken=`);
      if (parts.length === 2) return parts.pop().split(';').shift();
    }
    // 通过端口传给Elm
    app.ports.receiveCsrfToken.send(getCsrfToken());
    

第二步:封装通用HTTP请求函数

一次性封装带CSRF头的请求工具函数,后续所有业务请求直接调用封装后的函数即可,无需重复处理头信息:

import Http
import Json.Decode as D
import Json.Encode as E

-- 通用带CSRF头的请求构建函数,参数为存在Model中的csrfToken
authenticatedRequest : String -> String -> String -> Http.Body -> D.Decoder a -> Http.Request a
authenticatedRequest csrfToken method url body decoder =
  Http.request
    { method = method
    , url = url
    , headers = [ Http.header "X-CSRFTOKEN" csrfToken ]
    , body = body
    , expect = Http.expectJson decoder
    , timeout = Nothing
    , withCredentials = True -- 跨域请求时需要开启,同域可设为False
    }

-- 封装常用POST请求
csrfPost : String -> String -> E.Value -> D.Decoder a -> Cmd (Result Http.Error a)
csrfPost csrfToken url reqBody decoder =
  Http.send identity <|
    authenticatedRequest csrfToken "POST" url (Http.jsonBody reqBody) decoder

-- 封装常用PUT请求
csrfPut : String -> String -> E.Value -> D.Decoder a -> Cmd (Result Http.Error a)
csrfPut csrfToken url reqBody decoder =
  Http.send identity <|
    authenticatedRequest csrfToken "PUT" url (Http.jsonBody reqBody) decoder

-- 封装常用GET请求
csrfGet : String -> String -> D.Decoder a -> Cmd (Result Http.Error a)
csrfGet csrfToken url decoder =
  Http.send identity <|
    authenticatedRequest csrfToken "GET" url Http.emptyBody decoder

业务侧使用示例

后续发起请求时只需传入存在Model中的CSRF Token即可,无需再手动处理头信息:

-- 示例:提交用户信息
submitUserInfo : Model -> Cmd Msg
submitUserInfo model =
  csrfPost
    model.csrfToken
    "/api/user/"
    (E.object
      [ ("name", E.string model.inputName)
      , ("age", E.int model.inputAge)
      ]
    )
    userInfoDecoder

注意事项

  • 未稳定的Effect Manager API可以实现全局请求拦截,但官方不推荐在生产环境使用,封装工具函数是当前最稳妥的方案
  • 跨域场景下需要在Django侧配置CORS_ALLOW_CREDENTIALS = True,同时配置正确的CORS允许域名,不要使用通配符

内容的提问来源于stack exchange,提问作者Ulrich Schuster

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:54:01