在我們的前幾篇文章中,我們已經介紹了如何使用表單來捕獲用戶輸入數據,並通過 EmailJS 發送表單數據。今天,我們將深入探討如何利用 sessionStorage 來實現數據持久化,並結合加密技術來保護用戶的敏感信息。我們會比較不同的數據持久化選項,並且著重於如何加密數據以增強安全性。
在前端開發中,有多種選擇來存儲數據,常見的包括 localStorage、sessionStorage 和 cookies。我們在這裡比較它們的特點:
| 技術 | 有效範圍 | 持久性 | 容量 | 安全性 | 
|---|---|---|---|---|
| localStorage | 整個應用程序 | 永久存儲,直到被刪除 | 約 5-10 MB | 沒有自動加密,需手動加密 | 
| sessionStorage | 當前會話 | 在會話結束後清除 | 約 5-10 MB | 沒有自動加密,需手動加密 | 
| Cookies | 整個應用或特定域 | 可設定過期時間 | 約 4 KB | 可以設置 HttpOnly 和 Secure 標誌 | 
sessionStorage 的原因sessionStorage 適合存儲在當前會話期間需要保留的數據,且在用戶關閉瀏覽器後會自動清除。localStorage 小,但對於表單這樣的應用來說已經足夠。CryptoJS 對數據進行加密,從而保護敏感數據。接下來,我們將以 "Let’s Collaborate" 表單為例,展示如何使用 sessionStorage 進行加密和數據持久化。
首先,安裝 CryptoJS 用於加密和解密數據:
 npm install crypto-js 
為了保護數據,我們將使用一個加密密鑰來加密表單數據。在你的環境變數文件(.env)中,添加如下密鑰:
REACT_APP_SECRET_KEY=your_secret_key
接下來,我們先初始化表單數據,並填入到useForm。這裡我們將使用 sessionStorage 來持久化表單數據,確保它在當前瀏覽器會話中保存。
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import * as styles from '@/components/Form/ContactForm.module.scss';
import CryptoJS from 'crypto-js';
const ContactForm = () => {
    // 初始化表單數據狀態
    const [formData, setFormData] = useState({
        name: '',
        email: '',
        serviceItem: '',
        projectDetails: ''
    });
    // 使用 useForm hook 來管理表單
    const { register, handleSubmit, formState: { errors }, reset } = useForm({
        defaultValues: formData  // 使用初始狀態來填充表單
    });
    return (
        <form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
            {/* 其他表單項目 */}
        </form>
    );
};
formData:使用 useState 初始化表單數據。useForm:React Hook Form 的 useForm 用於管理表單的輸入和狀態。在頁面加載時,我們需要從 sessionStorage 中檢查是否已經保存了加密的表單數據,並將其解密後填充到表單中。
import { useEffect } from 'react';
// 從環境變數中讀取加密密鑰
const SECRET_KEY = process.env.REACT_APP_SECRET_KEY;
const ContactForm = () => {
    // Step 2: 從 sessionStorage 加載加密數據
    useEffect(() => {
        const savedData = sessionStorage.getItem('contactForm');
        if (savedData) {
            const bytes = CryptoJS.AES.decrypt(savedData, SECRET_KEY);
            const decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
            setFormData(decryptedData);
            reset(decryptedData);  // 重設表單數據
        }
    }, [reset]);
    return (
        <form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
            {/* 其他表單項目 */}
        </form>
    );
};
每次當用戶在表單中輸入或修改數據時,我們將這些數據加密並保存到 sessionStorage 中,以便在會話期間持續保存數據。
useEffect(() => {
    const encryptedData = CryptoJS.AES.encrypt(JSON.stringify(formData), SECRET_KEY).toString();
    sessionStorage.setItem('contactForm', encryptedData);
}, [formData]);
const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData((prevData) => ({
        ...prevData,
        [name]: value,
    }));
};
return (
   <form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
            <div className={styles.formGroup}>
                <label htmlFor="name">Name</label>
                <input
                    type="text"
                    {...register('name', { required: 'Name is required' })}
                    placeholder="Your Name"
                    value={formData.name}  // 綁定到狀態
                    onChange={handleInputChange}  // 監聽變更
                />
                {errors.name && <p className={styles.errorText}>{errors.name.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="email">Email</label>
                <input
                    type="email"
                    {...register('email', {
                        required: 'Email is required',
                        pattern: {
                            value: /\S+@\S+\.\S+/,
                            message: 'Enter a valid email',
                        },
                    })}
                    placeholder="Your Email"
                    value={formData.email}  // 綁定到狀態
                    onChange={handleInputChange}  // 監聽變更
                />
                {errors.email && <p className={styles.errorText}>{errors.email.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="serviceItem">Service Items</label>
                <select
                    {...register('serviceItem', { required: 'Please select a service item' })}
                    value={formData.serviceItem}  // 綁定到狀態
                    onChange={handleInputChange}  // 監聽變更
                >
                    <option value="">Select a service</option>
                    <option value="design">Design</option>
                    <option value="development">Development</option>
                    <option value="consultation">Consultation</option>
                </select>
                {errors.serviceItem && <p className={styles.errorText}>{errors.serviceItem.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="projectDetails">Project Details</label>
                <textarea
                    {...register('projectDetails', { required: 'Project details are required' })}
                    placeholder="Describe your project"
                    value={formData.projectDetails}  // 綁定到狀態
                    onChange={handleInputChange}  // 監聽變更
                ></textarea>
                {errors.projectDetails && <p className={styles.errorText}>{errors.projectDetails.message}</p>}
            </div>
        {/* 其他表單項目 */}
    </form>
);
sessionStorage在表單提交後,我們會清除 sessionStorage 中的表單數據,避免重複填充舊數據。
const onSubmit = (data) => {
        setIsSending(true); // 開始發送,設置 loading 狀態
        // EmailJS 發送邏輯
        const templateParams = {
            from_name: data.name,
            from_email: data.email,
            service: data.serviceItem,
            message: data.projectDetails,
        };
        emailjs
            .send(
                process.env.EMAILJS_SERVICE_ID,  // 使用環境變數中的 Service ID
                process.env.EMAILJS_TEMPLATE_ID,  // 使用環境變數中的 Template ID
                templateParams,
                process.env.EMAILJS_PUBLIC_KEY  // 使用環境變數中的 Public Key
            )
            .then(
                (response) => {
                    console.log('Email sent successfully!', response.status, response.text);
                    alert('Your message was sent successfully!');
                    sessionStorage.removeItem('contactForm');  // 提交後清除 sessionStorage
                    setIsSending(false); // 發送完成,重置 loading 狀態
                },
                (error) => {
                    console.log('Failed to send email...', error);
                    alert('There was an error sending your message.');
                    setIsSending(false); // 發送失敗,重置 loading 狀態
                }
            );
    };
在這篇文章中,我們學習了如何使用 sessionStorage 來持久化表單數據,並使用加密技術來保護用戶數據的安全性。sessionStorage 適合短期的數據存儲,當瀏覽器關閉後自動清除數據,這使其成為表單和購物車等短期使用數據的理想選擇。
✨ 流光館Luma<∕> ✨ 期待與你繼續探索更多技術知識!