美文网首页
05 - 使用 AJAX 通信

05 - 使用 AJAX 通信

作者: 勤劳的悄悄 | 来源:发表于2019-02-25 16:40 被阅读0次
01 - Clojure Web 程序基本结构.png

客户端使用 Ajax

引入依赖

;; Ajax 库
[cljs-ajax "0.7.4"]

;; 支持 JSON 格式的中间件
[ring-middleware-format "0.7.2"]

配置中间件

添加支持 JSON 格式的中间件(本段讲解,没有代码)

注意:因为我们将会为客户端 Ajax 请求设置 :format :json 选项,因此服务端收到的请求参数将会是下面这样:

:params {email jiesoul@gmail.com, password 12345678}

而我们希望的格式应该如下:

:params {:email jiesoul@gmail.com, :password 12345678}

解决方法是开启 ring-middleware-format 中间件的 :formats [:json-kw] 选项,他会自动为 JSON 数据设置关键字

(wrap-format/wrap-restful-format :formats [:json-kw])

代码

文件:src/soul_talk/core.clj

(ns soul-talk.core
  (:require 
    ......
    ;; 支持 JSON 格式的中间件
    [ring.middleware.format :as wrap-format]))


(def app
  (-> app-routes  
      (wrap-nocache)
      (wrap-reload)
      (wrap-webjars) 
      
      ;; 这行是添加的
      (wrap-format/wrap-restful-format :formats [:json-kw])

      (wrap-defaults (assoc-in site-defaults [:security :anti-forgery] false))))

(defn -main []
  (jetty/run-jetty app {:port 3000 :join? false}))

ClojureScript

改造 login.cljs ,加入 Ajax 功能

主要进行了以下几项修改

  • 创建了一个 login-data 变量,保存客户端登陆数据,他会通过 Ajax 被发送到服务端
  • 之前输入框丢失焦点后,仅仅将输入框和要使用的验证函数传给 validate-invalid ;现在还需要向 login-data 变量中添加数据
  • 之前输入框丢失焦点后,直接通过 id 获取组件 ,现在则是通过事件对象 e 获得组件
  • 之前点击提交按钮后,validate-form 直接从数据框中读取数据进行验证,现在从 JSON 变量中读取数据进行验证
  • 之前点击提交按钮,验证成功后,返回 true ,然后提交到服务器;现在验证成功后,通过 Ajax 提交数据,页面不刷新
  • 把客户端页面的 form 改为 div 元素

==注意:服务端登录无论成功还是失败,最后 Ajax 都会调用 haddler-ok 函数,那是因为服务端返回的状态码被转换成了 JSON 数据 {"status":404,"errors":"用户名密码不对"},而状态码总是 200,后面会改进这个问题==

修改 login.cljs

(ns soul-talk.login
  (:require [domina :as dom]
            [domina.events :as ev]
            [reagent.core :as reagent :refer [atom]]
            ;; 引入共享代码
            [soul-talk.auth-validate :as validate]
            ;; 引入 Ajax 支持
            [ajax.core :as ajax]))


(def login-data (atom {:email "" :password ""}))


;; 如果验证不成功,则在输入框上增加样式;
;; 如果验证成功,则移除样式
;; 这个函数,输入框失去焦点的时候被调用
(defn validate-invalid [input vali-fun]
  (if-not (vali-fun (.-value input))  ;; 验证函数传入文本,而不是 HTML 元素
    (dom/add-class! input "is-invalid")
    (dom/remove-class! input "is-invalid")))


;; Ajax 成功后调用
(defn handler-ok [response]
  (js/alert @login-data))

;; Ajax 失败后调用
(defn handler-error [{:keys [status status-text]}]
  (js/alert (sstr status status-text)))


(defn login! []
  (ajax/POST
    "/login"
    {:format        :json
     :headers       {"Accept" "application/transit+json"}
     :params        @login-data
     :handler       handler-ok
     :error-handler handler-error}))


;; 这个函数提交的时候被调用,类客户端验证输入格式是否正确
(defn validate-form []
  ;; 注意这里的变化
  ;; 数据不再是从元素中直接读取,而是从 JSON 数据中读取
  (if (and (validate/validate-email (:email @login-data))
           (validate/validate-passoword (:password @login-data)))

    ;; 注意这里的变化:之前验证成功返回 true ,则表单可以提交
    ;; 现在是调用 login! 函数,利用 ajax 从后台读取据,不提交也不刷新页面
    (login!)
    (do
      (js/alert "email和密码不合法")
      false)))



;; 组件化登陆表单
(defn login-component []
  [:div.container
   ;; 登陆表单
   [:form#loginForm.form-signin
    ;; 标题
    [:h1.h3.mb-3.font-weight-normal.text-center "Please sign in"]

    ;; Email 部分
    [:div.form-group
     ;; Email 标签
     [:label "Email address"]
     ;; Email 输入框
     [:input#email.form-control
      {:type        "text"
       :name        "email"
       :auto-focus  true
       :placeholder "Email Address"
       ;; 焦点丢失的时候,调用验证函数
       :on-blur   (fn [e]
                      (let [d (.. e -target)]
                        (swap! login-data assoc :email (.-value d))
                        (validate-invalid d validate/validate-email)))}]
     ;; 错误提示信息
     [:div.invalid-feedback "无效的 Email"]]


    ;; 密码部分
    [:div.form-group
     [:label "Password"]
     ;; 密码输入框
     [:input#password.form-control
      {:type        "password"
       :name        "password"
       :placeholder "password"
       ;; 焦点丢失的时候,调用验证函数
       ;; 之前的代码仅仅将元素和要使用的函数传给 validate-invalid
       ;; 现在还需要向 JSON 中添加数据
       ;; 此外,之前直接通过 id 获取组件 ,现在则是通过事件对象 e 获得组件
       :on-blur     (fn [e]
                      (let [d (.-target e)]
                        (swap! login-data assoc :password (.-value d))
                        (validate-invalid d validate/validate-passoword)))}]
     ;; 错误提示信息
     [:div.invalid-feedback "无效的密码"]]

    ;; “记住我” 复选框
    [:div.form-group.form-check
     [:input#rememeber.form-check-input {:type "checkbox"}]
     [:label "记住我"]]

    ;; 错误信息
    [:div#error.invalid-feedback]

    ;; 提交按钮
    [:input#submit.btn.btn-lg.btn-primary.btn-block
     {:type  "button"
      :value "登录"
      :on-click #(validate-form)}]

    ;; 版权信息
    [:p.mt-5.mb-3.text-muted "&copy @2018"]]])



;; 渲染登陆表单组件,并挂载到 `content` div元素上
(defn load-page []
  (reagent/render
    [login-component]
    (dom/by-id "content")))


(defn ^:export init []
  (if (and js/document
           (.-getElementById js/document))
    (load-page)))


Clojure

完成服务端的 Ajax 支持

修改登录 Handler,和之前的代码相比有以下变化:

  • 使用了共享代码中的验证函数
  • request 中添加了 :session 字段,但是没有任何意义,因为这个数据没有传输给其他函数
  • 登陆成功,直接给客户端返回了一个 200,其他处理有客户端完成
  • 登陆失败,给客户端返回 400 ,但是要注意:这里的 400 是以 JSON 格式返回的,因此客户端解析不出来
(ns soul-talk.core
  (:require
    ......
    ;; 响应简化库,这个库暂时没用了
    [ring.util.http-response :as resp]
    
    ;; 内置响应库
    [ring.util.response :as res]
    
    ;; 引入共享代码
    [soul-talk.auth-validate :as auth-validate]))
    
    
;; Post 登录数据
(defn handle-login [{:keys [params] :as request}]
  (let [email (:email params)
        password (:password params)]
    (cond
      ;; 使用共享代码中的函数,之前没有使用
      (not (auth-validate/validate-email email)) (res/response {:status 400 :errors "Email不合法"})
      (not (auth-validate/validate-passoword password)) (res/response {:status 400 :errors "密码不合法"})
      (and (= email "jiesoul@gmail.com")
           (= password "12345678"))
      (do
        ;; 这行代码没任何意义
        (assoc-in request [:session :identity] email)
        
        ;; 仅仅给客户端返回一个 200 状态码,有客户端完成页面跳转
        (res/response {:status :ok}))
      
      :else (res/response {:status 400 :errors "用户名密码不对"}))))

修改路由

修改了 login 请求的 POST 路由,请求参数改成在 Hadler 中提取(好像意义不大)

(def app-routes
  (routes
    (GET "/" request (home-handle request))
    (GET "/about" [] (str "这是关于我的页面"))
    (GET "/login" request (login-page request))
    
    ;; Post 路由修改
    ;; (POST "/login" [email password :as req] (handle-login email password req))
    (POST "/login" req (handle-login req)) 


    (GET "/logout" request (handle-logout request))
    (route/not-found error-page)))  

相关文章

  • 05 - 使用 AJAX 通信

    客户端使用 Ajax 引入依赖 配置中间件 添加支持 JSON 格式的中间件(本段讲解,没有代码) 注意:因为我们...

  • ajax

    ajax技术的原理是实例化; 使用此对象与后台通信。ajax通信的过程不会影响后续javascript的执行,从而...

  • 21 Ajax 与 Comet

    本章内容 使用 XMLHttpRequest对象 使用XMLHttpRequest事件 跨域 Ajax 通信的限制...

  • Ajax 与 Comet

    本章内容:使用 XMLHttpRequest对象、使用 XMLHttpRequest 事件、跨域 Ajax通信 2...

  • 学习使用jquery+ajax(01)

    layout: _poststitle: 学习使用jquery+ajax(01)date: 2017-08-05 ...

  • ajax的工作原理

    一、什么是ajax ajax是一种异步通信技术。在ajax出现之前,客户端与服务端之间直接通信。引入ajax之后,...

  • ajax学习总结

    1、什么是ajax? ajax是一种可以不刷新页面,而实现与服务端通信的的方式,使用ajax的主要方式是XMLHt...

  • Web学习之跨域问题及解决方案

    在做前端开发时,我们时常使用ajax与服务器通信获取资源,享受ajax便利的同时,也知道它有限制:跨域安全限制,即...

  • ajax应用

    2019-05-29 Ajax简介 ​ Ajax(Asynchronous Javascript And XM...

  • 大连滕泰科技学习笔记2020-07-02

    1,ajax的原生j是编写? 1,1 什么是ajax?异步通信异步java scirpt xml 通信。网页访问的...

网友评论

      本文标题:05 - 使用 AJAX 通信

      本文链接:https://www.haomeiwen.com/subject/ibpwyqtx.html