中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript怎么實現前后端分離

發布時間:2022-03-23 14:23:39 來源:億速云 閱讀:493 作者:iii 欄目:web開發

本篇內容介紹了“JavaScript怎么實現前后端分離”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

前后端分離案例

現在把自己當成是前端,要開發一個前后分離的簡單頁面,用于展示學生信息列表

第一步

編寫一個用于展示表格的靜態頁面

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>

    </head>
    <body>
        <table id="tab" border="1">
            <tr>
                <th>編號</th>
                <th>名字</th>
                <th>年齡</th>
                <th>性別</th>
            </tr>
        </table>
        <button onclick="req()">請求數據</button>
        <img id="img" />
    </body>
</html>

不啟動tomcat直接在編輯器中打開即可訪問,此時他就是一個靜態網頁,而我們的編輯器就是一個HTTP服務器,可以響應靜態網頁

第二步

引入jquery使得ajax編寫更方便

<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>

第三步

編寫ajax,向服務器發送請求

第四步

將數據展示到頁面上

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    </head>
    <body>
        
        <table id="tab" border="1">
            <tr>
                <th>編號</th>
                <th>名字</th>
                <th>年齡</th>
                <th>性別</th>
            </tr>
        </table>
        <button onclick="req()">請求數據</button>
        <img id="img" />
    </body>
    <script>
        function req(){
            document.getElementById("img").src = "img/timg.gif";
            $.ajax({
                url:"http://localhost:8080/MyServer/getData",
                success:function(data){
                    console.log(data);
                    document.body.insertAdjacentHTML("beforeend","<h2>%</h2>".replace("%",data));
                    document.getElementById("img").src = "";    
                },
                error:function(err){
                    console.log(err);
                    document.getElementById("img").src = "";    
                }
            });
        }
    </script>
</html>

現在身份切換回后端開發用于獲取表格數據的接口

  1. 創建web項目

  2. 創建Servlet

  3. 引入fastjson

  4. 創建一個bean類

  5. 創建一堆bean放入列表中

  6. 將列表轉為json字符串 返回給前端

Servlet代碼

package com.kkb;

import java.io.IOException;

public class AServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
    }
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        String s = "{\"name\":\"jack\"}";
        response.getWriter().println(s);
    }
}

啟動服務,測試訪問,會發現頁面上沒有顯示服務器返回的結果&hellip;.

跨越問題

打開瀏覽器檢查頁面會發現沒有輸出服務器返回的消息而是,出現了一個錯誤信息,這就是前后端分離最常見的跨越問題

什么是跨域

跨越問題之所以產生是因為瀏覽器都遵循了同源策略

同源策略:

同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。

同源策略是瀏覽器的行為,是為了保護本地數據不被JavaScript代碼獲取回來的數據污染,瀏覽器會先發送OPTION請求進行預檢查,判斷服務器是否允許跨域,如果允許才發送真正的請求,否則拋出異常。

簡單的說:

同源策略是瀏覽器的核心安全機制,其不允許在頁面中解析執行來自其他服務器數據

如何判斷是否跨域

當一個請求url的協議、域名、端口三者之間任意一個與當前頁面url不同即為跨域

同源限制:
  1. 無法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB

  2. 無法向非同源地址發送 AJAX 請求

什么時候產生跨域問題:

瀏覽器在解析執行一個網頁時,如果頁面中的js代碼請求了另一個非同源的資源,則會產生跨越問題

而瀏覽器直接跳轉另一個非同源的地址時不會有跨域問題

解決跨越問題

既然禁止跨域問題是瀏覽器的行為,那么只需要設置瀏覽器允許解析跨域請求的數據即可,但是這個設置必須放在服務器端,由服務器端來判斷對方是否可信任

在響應頭中添加一個字段,告訴瀏覽器,某個服務器是可信的

package com.kkb;

import java.io.IOException;

public class AServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        response.setHeader("Access-Control-Allow-Origin","*");
        String s = "{\"name\":\"jack\"}";
        response.getWriter().println(s);
    }
}

其值可以是某個或多個指定的域名,也可以是*表示信任所有地址

其他相關設置

//指定允許其他域名訪問
'Access-Control-Allow-Origin:http://XXX.XXX.XXX'//一般用法(*,指定域,動態設置),注意*不允許攜帶認證頭和cookies
//預檢查間隔時間
'Access-Control-Max-Age: 1800'
//允許的請求類型
'Access-Control-Allow-Methods:GET,POST,PUT,POST'
//列出必須攜帶的字段
'Access-Control-Allow-Headers:x-requested-with,content-type'

解決了跨越問題后再來完善上面的案例

Servlet代碼:
package com.kkb;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.util.ArrayList;

public class AServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //允許來自任何主機的跨越訪問
        response.setHeader("Access-Control-Allow-Origin","*");
                //設置響應類型為json數據
        response.setContentType("application/json;charset=utf-8");

        //學生信息
        ArrayList<Student> students = new ArrayList<>();

        Student stu1 = new Student("s1","jack",20,"man");
        Student stu2 = new Student("s2","tom",22,"girl");
        Student stu3 = new Student("s3","jerry",10,"woman");
        Student stu4 = new Student("s4","scot",24,"boy");
        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        students.add(stu4);
        response.getWriter().println(JSON.toJSONString(JSON.toJSONString(students)));
    }
}
HTML代碼
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    </head>
    <body>
        <table id="tab" border="1">
            <tr>
                <th>編號</th>
                <th>名字</th>
                <th>年齡</th>
                <th>性別</th>
            </tr>
        </table>
        <button onclick="req()">請求數據</button>
        <img id="img" />
    </body>
    <script>
        function req(){
            document.getElementById("img").src = "img/timg.gif";
            $.ajax({
                url:"http://localhost:8080/MyServer/getData",
                success:function(data){
                    data = JSON.parse(data)
                    console.log(data)
                    for (var i = 0; i < data.length; i++) { 
                        a = data[i];
                        var row = "<tr><td>id</td><td>name</td><td>age</td><td>gender</td></tr>"
                            row = row.replace("id",a.id);
                            row = row.replace("name",a.name);
                            row = row.replace("age",a.age);
                            row = row.replace("gender",a.gender);   
                            document.getElementById("tab").insertAdjacentHTML("beforeend",row);
                    }
                    document.getElementById("img").src = "";    
                },
                error:function(err){
                    console.log(err);
                    document.getElementById("img").src = "";    
                }
            });
        }
    </script>
</html>

一個簡單的前后端分離項目就搞定了

補充:cookie跨域

默認情況下cookie是不允許跨域傳輸的.可以通過以下方式來解決

第一步

瀏覽器端設置允許cookie跨域

第二步

服務器端在響應中添加字段,說明允許cookie跨域

該值只能是true,為false無效,默認為false

#'Access-Control-Allow-Credentials:true'

狀態保持問題

在傳統的項目中我們利用,session+cookie來保持用戶的登錄狀態,但這在前后端分離項目中出現了問題;

sessionid是使用cookie存儲在客戶端的,而cookie遵守同源策略,只在同源的請求中有效,這就導致了問題出現:

前后端分離后,session+cookie的問題

  • 前后端分離后靜態資源完全可能(而且經常....)部署到另一個域下,導致cookie失效,例如這樣:

在www.baidu.com中設置的cookie是不會自動發送到cloud.baodu.comde

雖然我們可以在cookie中指定domain來解決,但是cookie必須針對性的設置作用域

這對于有多個不同域要共享cookie時,可操作性差,難以維護

  • 上述問題出現在前后端分離的web項目中,對于前后端分離的原生CS結構項目而言,很多客戶端默認是不處理session和cookie的,需要進行相應的設置

  • 在分布式或集群的項目中,共享session和cookie也是一大問題,必須引入第三方來完成session的存儲和共享(也可通過中間層做cookie轉發如Nginx.Node.js),這也是傳統單體服務無法支持分布式和集群的問題所在

正因為有這些問題,導致session+cookie的方式在某些項目中使用起來變得很麻煩,這時候就需要一種新的狀態維持的方式;

JWT

JWT全稱(json WEB token),是基于json數據結構的數據驗證方式,其本質是對json數據進行加密后產生的字符串

JWT的亮點:

  • 安全

  • 穩定

  • 易用

  • 支持 JSON

JWT是如何做的?

回顧,之所以使用session和cookie是因為HTTP的無狀態性質,導致服務器無法識別多次請求是否來自同一個用戶

JWT可以對用戶信息進行加密生成一個字符串,下發到客戶端,客戶端在后續請求中攜帶該字符串,服務器解析后取出用戶信息,從而完成用戶身份的識別,如下圖:

session共享和JWT在集群中的不同

JWT的數據結構

JWT是一個很長的字符串,分為成三個部分,中間用點.隔開注意; JWT 內部是沒有換行的,這里只是為了便于展示,將它寫成了幾行。

三個組成部分如下:

  • Header(頭部)

  • Payload(負載)

  • Signature(簽名)

Header 部分是一個 JSON 對象,描述 JWT 的元數據,例如簽名算法等,像下面這樣:

{
  "alg": "HS256",
  "typ": "JWT"
}

alg屬性表示簽名的算法,默認是 HMAC SHA256;

typ屬性表示這個令牌(token)的類型統一寫為JWT

最后使用base64URL算法轉換為字符串;

Payload

Payload 部分也是一個 JSON 對象,用來存放真正需要傳遞的數據,JWT 規定了7個保留字段,如下:

iss (issuer):簽發人
exp (expiration time):過期時間
sub (subject):主題
aud (audience):受眾
nbf (Not Before):生效時間
iat (Issued At):簽發時間
jti (JWT ID):編號

服務器需要在Payload中添加用于識別用戶身份的數據,也是鍵值對形式,注意不可使用保留字段,像下面這樣

{
  "sub": "test JWT",
  "name": "jerry",
  "isadmin": true
}

Payload同樣使用base64URL算法轉換為字符串;

強調:Payload數據默是不加密的,攻擊者可以通過相同的方式解析獲取

若要將用戶的關鍵數據放入其中則必須對其進行額外的加密

Signature

部分是對前兩部分的簽名,防止數據篡改。

簽名時需要指定一個密鑰(secret)。密鑰只有服務器才知道,不能泄露給用戶。然后使用 Header 里面指定的簽名算法(默認是 HMAC SHA256),按照下面的方式產生簽名。

signature = HMACSHA256(base64UrlEncode(header) + "." +  base64UrlEncode(payload),  secret)

最后把 Header、Payload、Signature 三個部分拼成一個字符串,每個部分之間用"點".分隔返回給用戶;

總結:

JWT的優點:

滿足REST Full的無狀態要求(為了提高系統的擴展性,REST要求所有信息由請求端來提供,如此才使得JWT成為了分布式,集群構架的首選方式)

在分布式,集群系統中使身份驗證變得非常簡單

可用于其他數據交換

合理的使用可減少數據庫查詢次數

JWT的缺點:

對于同樣的數據JWT整體大小超過同樣數據的cookie,這會增加網絡負擔

服務器每次解析JWT都需要再次執行對應的算法,這將增加系統負擔

在傳統單體服務,和WEBApp形式的前后端分離項目中使用JWT反而不如Session+cookie

注意事項:
  • JWT的payload部分是不加密的,如果要放入關鍵數據則必須對其進行加密,或是將最后的JWT整體加密

  • JWT本身用于認證,一旦泄露,則任何人都可以使用該令牌,獲得其包含的所有權限,為了提高安全性.JWT的有效期不應太長,對于一些非常權限,建議在請求時再次驗證

Java中JWT的使用:

懂得原理了后我們完全可以自己來實現,但是沒有必要,下面是目前用的較多的一個開源庫

使用JWT的步驟總體分為三步

  1. 生成JWT

  2. 驗證JWT

  3. 提取數據

案例:

package com.kkb;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class JWTTool {
    //自定義密鑰
    public static final String secretKey = "askjdksadjkasdakjshdjkasdkAakjshdjasdjs";

    /***
     *
     * @param secretKey 密鑰
     * @param data 用戶數據
     * @param expireTime 有效期
     * @return
     */
    public String getJWTWithHMAC256(String secretKey, HashMap<String, String> data,long expireTime){
        //指定JWT所使用的簽名算法
        Algorithm algorithm = Algorithm.HMAC256(secretKey);

        JWTCreator.Builder token = JWT.create()//創建token
                .withIssuer("com.kkb")//指定簽發人
                .withExpiresAt(new Date(expireTime));//有效時間
        //添加自定義數據
        if (data != null){
            for (Map.Entry<String, String> a :data.entrySet()) {
                token.withClaim(a.getKey(),a.getValue());
            }
        }
        return token.sign(algorithm);
    }

    public boolean verifyTokenWithHMAC256(String token,String secretKey){
        try{
            Algorithm algorithm = Algorithm.HMAC256(secretKey);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("com.kkb")
                    .build();
            verifier.verify(token);
            return true;
        }catch (JWTVerificationException e){
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) {
        JWTTool jwtTool = new JWTTool();

        //要添加到token中的數據
        HashMap<String,String> data = new HashMap<>();
        data.put("user","jerry");
        data.put("isAdmin","true");

        //有效期
        long expiresTime = new Date().getTime() + 1000 * 60 * 60;

        //生成token
        String token = jwtTool.getJWTWithHMAC256(secretKey,data,expiresTime);
        System.out.println(token);

        //驗證token
        //If the token has an invalid signature or the Claim requirement is not met
        if (jwtTool.verifyTokenWithHMAC256(token,secretKey)){
            System.out.println("token 有效");
            try{
                //提取數據
                DecodedJWT decode = JWT.decode(token);
                System.out.println("數據:"+decode.getClaim("user").asString());
                System.out.println("數據:"+decode.getClaim("isAdmin").asString());
                System.out.println("簽發:"+decode.getIssuer());
                System.out.println("有效期"+decode.getExpiresAt());

            }catch (JWTDecodeException e){
                //If the token has an invalid syntax or the header or payload are not JSONs,
                System.out.println("解析token失敗");
            }
        }else {
            System.out.println("token 無效");
        }
    }
}

“JavaScript怎么實現前后端分離”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

石林| 兴业县| 弋阳县| 屏东市| 卓资县| 磴口县| 渭源县| 海安县| 淮北市| 北辰区| 双峰县| 沙湾县| 宁化县| 广东省| 同德县| 津南区| 讷河市| 泰宁县| 蒲江县| 高阳县| 阜平县| 平顺县| 拜泉县| 彰武县| 双鸭山市| 乌兰察布市| 镇平县| 望城县| 兴业县| 神农架林区| 竹山县| 灵丘县| 三台县| 微山县| 迁安市| 壤塘县| 衡东县| 娱乐| 梓潼县| 股票| 资溪县|