引言

随着全球数字化进程的加速,电子签证(e-Visa)系统已成为各国出入境管理的重要组成部分。电子签证支付系统作为整个流程中的关键环节,其稳定性和安全性直接关系到用户体验和国家形象。本文将通过详细的实训指导,帮助读者全面掌握电子签证支付系统的核心流程,并针对常见问题提供有效的应对策略。

一、电子签证支付系统概述

1.1 电子签证支付系统定义

电子签证支付系统是指申请人在线提交签证申请后,通过互联网完成费用支付的数字化系统。该系统通常包括支付网关集成、多币种处理、安全认证和交易记录管理等功能。

1.2 系统架构与组件

一个典型的电子签证支付系统包含以下核心组件:

  • 前端界面:用户提交申请和支付的网页或移动应用
  • 支付网关:连接银行或第三方支付平台的接口
  • 签证处理引擎:验证申请信息和处理支付状态
  • 数据库:存储交易记录和申请信息
  • 安全模块:加密通信、防欺诈检测等

1.3 技术栈示例

现代电子签证支付系统通常采用以下技术栈:

// 前端示例(React + Stripe集成)
import React, { useState } from 'react';
import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';

const PaymentForm = ({ amount, currency, onSuccess }) => {
  const stripe = useStripe();
  const elements = useElements();
  const [error, setError] = useState(null);
  const [processing, setProcessing] = useState(false);

  const handleSubmit = async (event) => {
    event.preventDefault();
    setProcessing(true);
    
    if (!stripe || !elements) {
      return;
    }

    const cardElement = elements.getElement(CardElement);
    
    const { error, paymentMethod } = await stripe.createPaymentMethod({
      type: 'card',
      card: cardElement,
    });

    if (error) {
      setError(error.message);
      setProcessing(false);
    } else {
      // 发送支付信息到后端
      const response = await fetch('/api/payment', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          paymentMethodId: paymentMethod.id,
          amount: amount * 100, // 转换为最小货币单位
          currency: currency,
          visaApplicationId: 'VISA-2024-001'
        })
      });

      const result = await response.json();
      
      if (result.success) {
        onSuccess(result.transactionId);
      } else {
        setError(result.error || '支付失败');
      }
      setProcessing(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="payment-form">
      <CardElement options={{ hidePostalCode: true }} />
      {error && <div className="error">{error}</div>}
      <button type="submit" disabled={!stripe || processing}>
        {processing ? '处理中...' : `支付 $${amount}`}
      </button>
    </form>
  );
};

二、核心流程详解

2.1 用户申请流程

电子签证支付通常遵循以下步骤:

  1. 信息填写:用户在线填写签证申请表
  2. 材料上传:上传护照扫描件、照片等必要文件
  3. 费用计算:系统根据签证类型、国籍、停留时间自动计算费用
  4. 支付选择:选择支付方式(信用卡、借记卡、电子钱包等)
  5. 支付处理:通过支付网关完成交易
  6. 结果反馈:显示支付成功/失败信息
  7. 后续处理:系统自动将支付状态同步至签证处理系统

2.2 支付网关集成流程

支付网关的集成是技术实现的关键:

# 后端支付处理示例(Python + Stripe)
import stripe
from flask import Flask, request, jsonify
import os

app = Flask(__name__)
stripe.api_key = os.getenv('STRIPE_SECRET_KEY')

@app.route('/api/payment', methods=['POST'])
def process_payment():
    data = request.json
    
    try:
        # 创建支付意图
        payment_intent = stripe.PaymentIntent.create(
            amount=data['amount'],
            currency=data['currency'],
            payment_method=data['paymentMethodId'],
            confirm=True,
            metadata={
                'visa_application_id': data['visaApplicationId'],
                'applicant_name': data.get('applicantName', ''),
                'visa_type': data.get('visaType', '')
            },
            return_url='https://visa.example.com/payment/success'
        )
        
        # 验证支付状态
        if payment_intent.status == 'succeeded':
            # 记录交易到数据库
            transaction = {
                'transaction_id': payment_intent.id,
                'amount': data['amount'] / 100,
                'currency': data['currency'],
                'status': 'completed',
                'visa_application_id': data['visaApplicationId'],
                'created_at': datetime.now()
            }
            
            # 更新签证申请状态
            update_visa_application_status(data['visaApplicationId'], 'payment_completed')
            
            return jsonify({
                'success': True,
                'transactionId': payment_intent.id,
                'status': 'completed'
            })
        else:
            return jsonify({
                'success': False,
                'error': '支付未完成'
            })
            
    except stripe.error.CardError as e:
        return jsonify({
            'success': False,
            'error': f'卡错误: {e.user_message}'
        })
    except stripe.error.RateLimitError as e:
        return jsonify({
            'success': False,
            'error': '请求过于频繁'
        })
    except stripe.error.InvalidRequestError as e:
        return jsonify({
            'success': False,
            'error': '无效请求'
        })
    except Exception as e:
        return jsonify({
            'success': False,
            'error': '系统错误'
        })

def update_visa_application_status(application_id, status):
    # 数据库操作示例
    # 这里应该连接数据库并更新状态
    print(f"更新申请 {application_id} 状态为 {status}")

2.3 多币种处理

电子签证系统需要支持多种货币:

// 多币种处理示例
const currencyRates = {
  'USD': 1,
  'EUR': 0.92,
  'GBP': 0.79,
  'JPY': 149.5,
  'CNY': 7.24
};

const calculateFee = (baseFee, applicantCountry, visaType) => {
  // 根据申请人国籍和签证类型计算费用
  let fee = baseFee;
  
  // 特定国家的费用调整
  if (applicantCountry === 'USA') {
    fee = baseFee * 1.2; // 美国申请人额外20%
  } else if (applicantCountry === 'CHN') {
    fee = baseFee * 0.9; // 中国申请人9折
  }
  
  // 签证类型调整
  if (visaType === 'tourist') {
    fee = fee * 0.8; // 旅游签证8折
  } else if (visaType === 'business') {
    fee = fee * 1.5; // 商务签证1.5倍
  }
  
  return fee;
};

const convertCurrency = (amount, fromCurrency, toCurrency) => {
  if (fromCurrency === toCurrency) return amount;
  
  const rate = currencyRates[toCurrency] / currencyRates[fromCurrency];
  return Math.round(amount * rate * 100) / 100; // 保留两位小数
};

三、安全机制与合规要求

3.1 PCI DSS合规

支付卡行业数据安全标准(PCI DSS)是必须遵守的规范:

# PCI DSS合规示例 - 安全存储卡信息
from cryptography.fernet import Fernet
import hashlib
import hmac

class SecureCardStorage:
    def __init__(self):
        # 密钥管理 - 实际生产中应使用HSM或云KMS
        self.encryption_key = Fernet.generate_key()
        self.cipher = Fernet(self.encryption_key)
        
    def tokenize_card(self, card_number, expiry_date, cvv):
        """
        令牌化处理 - 不存储完整卡号
        """
        # 生成令牌(实际应用中使用专业令牌化服务)
        token = hashlib.sha256(f"{card_number}{expiry_date}".encode()).hexdigest()
        
        # 加密敏感信息
        encrypted_cvv = self.cipher.encrypt(cvv.encode())
        
        return {
            'card_token': token[:16],  # 只存储前16位令牌
            'expiry_date': expiry_date,
            'encrypted_cvv': encrypted_cvv.decode(),
            'last_four': card_number[-4:]
        }
    
    def verify_payment(self, token, amount, currency):
        """
        验证支付请求
        """
        # 检查令牌有效性
        if not self.validate_token(token):
            return False, "无效的支付令牌"
        
        # 验证金额和货币
        if amount <= 0:
            return False, "无效的金额"
        
        # 检查货币支持
        supported_currencies = ['USD', 'EUR', 'GBP', 'JPY', 'CNY']
        if currency not in supported_currencies:
            return False, f"不支持的货币: {currency}"
        
        return True, "验证通过"
    
    def validate_token(self, token):
        """
        验证令牌格式
        """
        if not token or len(token) != 16:
            return False
        
        # 检查是否为十六进制
        try:
            int(token, 16)
            return True
        except ValueError:
            return False

3.2 防欺诈检测

# 简单的防欺诈检测示例
class FraudDetection:
    def __init__(self):
        self.suspicious_patterns = []
        
    def analyze_transaction(self, transaction_data):
        """
        分析交易是否存在欺诈风险
        """
        risk_score = 0
        alerts = []
        
        # 检查IP地址
        if self.is_suspicious_ip(transaction_data.get('ip_address')):
            risk_score += 30
            alerts.append("可疑IP地址")
        
        # 检查交易频率
        if self.check_transaction_frequency(transaction_data.get('user_id')):
            risk_score += 25
            alerts.append("交易频率异常")
        
        # 检查金额异常
        if transaction_data.get('amount', 0) > 10000:  # 假设10000为阈值
            risk_score += 20
            alerts.append("大额交易")
        
        # 检查新设备
        if transaction_data.get('is_new_device', False):
            risk_score += 15
            alerts.append("新设备登录")
        
        # 检查时间异常(如深夜交易)
        hour = transaction_data.get('transaction_hour', 0)
        if hour < 6 or hour > 22:
            risk_score += 10
            alerts.append("非正常交易时间")
        
        # 决策
        if risk_score >= 60:
            return {
                'status': 'blocked',
                'risk_score': risk_score,
                'alerts': alerts,
                'message': '交易被阻止 - 高风险'
            }
        elif risk_score >= 30:
            return {
                'status': 'review',
                'risk_score': risk_score,
                'alerts': alerts,
                'message': '需要人工审核'
            }
        else:
            return {
                'status': 'approved',
                'risk_score': risk_score,
                'alerts': [],
                'message': '交易通过'
            }
    
    def is_suspicious_ip(self, ip_address):
        """
        检查IP是否可疑(示例)
        """
        if not ip_address:
            return True
        
        # 示例:检查是否来自高风险国家
        high_risk_countries = ['CN', 'RU', 'KP']  # 示例国家代码
        # 实际应用中需要IP地理位置服务
        
        return False  # 简化示例
    
    def check_transaction_frequency(self, user_id):
        """
        检查用户交易频率
        """
        # 实际应用中需要查询数据库
        # 这里返回示例数据
        return False  # 简化示例

四、常见问题及应对策略

4.1 支付失败问题

问题描述

用户支付过程中遇到各种错误,如”卡被拒绝”、”余额不足”、”网络错误”等。

应对策略

  1. 错误分类处理
# 支付错误分类处理
def handle_payment_error(error_code, error_message):
    error_mapping = {
        'card_declined': {
            'user_message': '您的卡被拒绝。请检查卡信息或联系发卡行。',
            'action': '建议更换支付方式',
            'log_level': 'warning'
        },
        'insufficient_funds': {
            'user_message': '余额不足。请确保卡内有足够资金。',
            'action': '建议使用其他卡或充值',
            'log_level': 'info'
        },
        'invalid_cvc': {
            'user_message': '安全码错误。请检查CVC/CVV码。',
            'action': '重新输入安全码',
            'log_level': 'warning'
        },
        'expired_card': {
            'user_message': '卡已过期。请使用有效期内的卡。',
            'action': '更新卡信息',
            'log_level': 'warning'
        },
        'network_error': {
            'user_message': '网络连接问题。请检查网络后重试。',
            'action': '重试支付',
            'log_level': 'error'
        }
    }
    
    error_info = error_mapping.get(error_code, {
        'user_message': f'支付失败: {error_message}',
        'action': '联系客服',
        'log_level': 'error'
    })
    
    # 记录日志
    log_payment_error(error_code, error_message, error_info['log_level'])
    
    return error_info
  1. 用户界面优化
    • 提供清晰的错误提示
    • 显示可操作的解决方案
    • 提供备用支付方式选项
    • 设置重试机制(限制次数)

4.2 支付成功但状态未更新

问题描述

用户支付成功,但系统显示支付失败或仍在处理中。

应对策略

  1. 状态同步机制
# 支付状态同步服务
import time
from threading import Thread
import queue

class PaymentStatusSync:
    def __init__(self):
        self.pending_transactions = queue.Queue()
        self.sync_interval = 30  # 30秒同步一次
        
    def add_pending_transaction(self, transaction_id, visa_application_id):
        """添加待同步的交易"""
        self.pending_transactions.put({
            'transaction_id': transaction_id,
            'visa_application_id': visa_application_id,
            'retry_count': 0,
            'created_at': time.time()
        })
    
    def start_sync_service(self):
        """启动同步服务"""
        thread = Thread(target=self._sync_loop, daemon=True)
        thread.start()
    
    def _sync_loop(self):
        """同步循环"""
        while True:
            try:
                # 从队列获取待处理交易
                transaction = self.pending_transactions.get(timeout=1)
                
                # 检查是否超时(超过1小时未处理)
                if time.time() - transaction['created_at'] > 3600:
                    self._handle_timeout(transaction)
                    continue
                
                # 尝试同步状态
                success = self._sync_transaction_status(transaction)
                
                if success:
                    # 同步成功,从队列移除
                    self.pending_transactions.task_done()
                else:
                    # 同步失败,重新入队(增加重试次数)
                    transaction['retry_count'] += 1
                    if transaction['retry_count'] < 5:  # 最多重试5次
                        self.pending_transactions.put(transaction)
                    else:
                        # 超过重试次数,标记为失败
                        self._mark_as_failed(transaction)
                        self.pending_transactions.task_done()
                
            except queue.Empty:
                time.sleep(1)
    
    def _sync_transaction_status(self, transaction):
        """同步单个交易状态"""
        try:
            # 调用支付网关API查询状态
            payment_status = self.query_payment_gateway(
                transaction['transaction_id']
            )
            
            if payment_status == 'completed':
                # 更新数据库
                self.update_visa_application_status(
                    transaction['visa_application_id'],
                    'payment_completed'
                )
                return True
            elif payment_status == 'failed':
                self.update_visa_application_status(
                    transaction['visa_application_id'],
                    'payment_failed'
                )
                return True
            else:
                # 状态未定,继续等待
                return False
                
        except Exception as e:
            print(f"同步失败: {e}")
            return False
    
    def query_payment_gateway(self, transaction_id):
        """查询支付网关状态(示例)"""
        # 实际调用支付网关API
        # 这里返回模拟数据
        import random
        statuses = ['pending', 'completed', 'failed']
        return random.choice(statuses)
    
    def update_visa_application_status(self, application_id, status):
        """更新签证申请状态"""
        # 数据库操作
        print(f"更新申请 {application_id} 状态为 {status}")
    
    def _handle_timeout(self, transaction):
        """处理超时交易"""
        print(f"交易 {transaction['transaction_id']} 超时")
        # 发送通知给管理员
        self.send_admin_alert(f"交易超时: {transaction['transaction_id']}")
    
    def _mark_as_failed(self, transaction):
        """标记为失败"""
        print(f"标记交易 {transaction['transaction_id']} 为失败")
        self.update_visa_application_status(
            transaction['visa_application_id'],
            'payment_failed'
        )
  1. 用户沟通策略
    • 自动发送支付确认邮件
    • 提供交易查询页面
    • 设置客服热线
    • 建立状态查询API

4.3 多币种处理问题

问题描述

汇率波动导致费用计算错误,或用户对费用明细不理解。

应对策略

  1. 实时汇率更新
# 汇率更新服务
import requests
import time
from datetime import datetime, timedelta

class CurrencyRateManager:
    def __init__(self):
        self.rates = {}
        self.last_update = None
        self.update_interval = 3600  # 每小时更新一次
        
    def get_rate(self, from_currency, to_currency):
        """获取实时汇率"""
        if self._needs_update():
            self._update_rates()
        
        if from_currency == to_currency:
            return 1.0
        
        # 交叉汇率计算
        if from_currency in self.rates and to_currency in self.rates:
            base_rate = self.rates[from_currency]
            target_rate = self.rates[to_currency]
            return target_rate / base_rate
        
        return None
    
    def _needs_update(self):
        """检查是否需要更新汇率"""
        if not self.last_update:
            return True
        
        now = datetime.now()
        return (now - self.last_update).total_seconds() > self.update_interval
    
    def _update_rates(self):
        """从API更新汇率"""
        try:
            # 使用免费汇率API(示例)
            response = requests.get(
                'https://api.exchangerate-api.com/v4/latest/USD',
                timeout=10
            )
            
            if response.status_code == 200:
                data = response.json()
                self.rates = data['rates']
                self.last_update = datetime.now()
                print(f"汇率更新成功: {len(self.rates)} 种货币")
            else:
                print(f"汇率更新失败: {response.status_code}")
                
        except Exception as e:
            print(f"汇率更新错误: {e}")
    
    def calculate_final_amount(self, base_amount, from_currency, to_currency):
        """计算最终金额"""
        rate = self.get_rate(from_currency, to_currency)
        if rate is None:
            return None
        
        final_amount = base_amount * rate
        # 四舍五入到两位小数
        return round(final_amount, 2)
  1. 费用透明度
    • 明确显示基础费用、税费、服务费
    • 提供费用计算示例
    • 允许用户选择显示货币
    • 提供汇率说明

4.4 网络与连接问题

问题描述

用户网络不稳定导致支付中断。

应对策略

  1. 断点续传机制
// 前端断点续传示例
class PaymentResilience {
    constructor() {
        this.maxRetries = 3;
        this.retryDelay = 1000; // 1秒
    }
    
    async resilientPayment(paymentData, onProgress) {
        let lastError = null;
        
        for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
            try {
                if (onProgress) {
                    onProgress(`尝试支付 (第 ${attempt} 次)...`);
                }
                
                const result = await this.processPayment(paymentData);
                
                if (result.success) {
                    return result;
                } else {
                    lastError = result.error;
                    
                    // 检查是否为可重试错误
                    if (this.isRetryableError(result.error)) {
                        if (attempt < this.maxRetries) {
                            // 等待后重试
                            await this.sleep(this.retryDelay * attempt);
                            continue;
                        }
                    } else {
                        // 不可重试错误,立即返回
                        break;
                    }
                }
            } catch (error) {
                lastError = error.message;
                
                // 网络错误可重试
                if (this.isNetworkError(error) && attempt < this.maxRetries) {
                    await this.sleep(this.retryDelay * attempt);
                    continue;
                } else {
                    break;
                }
            }
        }
        
        return {
            success: false,
            error: lastError || '支付失败',
            attempts: this.maxRetries
        };
    }
    
    async processPayment(paymentData) {
        // 实际支付处理
        const response = await fetch('/api/payment', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(paymentData),
            signal: AbortSignal.timeout(30000) // 30秒超时
        });
        
        return await response.json();
    }
    
    isRetryableError(error) {
        const retryableErrors = [
            'timeout',
            'network_error',
            'service_unavailable',
            'rate_limit_exceeded'
        ];
        
        return retryableErrors.some(e => 
            error.toLowerCase().includes(e.toLowerCase())
        );
    }
    
    isNetworkError(error) {
        return error.includes('network') || 
               error.includes('timeout') ||
               error.includes('fetch');
    }
    
    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}
  1. 离线处理
    • 保存支付草稿
    • 提供支付状态查询
    • 设置支付有效期
    • 发送支付提醒

五、实训操作指南

5.1 环境搭建

# 创建虚拟环境
python -m venv visa_payment_env
source visa_payment_env/bin/activate  # Linux/Mac
# visa_payment_env\Scripts\activate  # Windows

# 安装依赖
pip install flask stripe requests cryptography

# 创建项目结构
mkdir visa_payment_system
cd visa_payment_system
mkdir templates static
touch app.py config.py requirements.txt

5.2 完整示例项目

# app.py - 完整示例
from flask import Flask, render_template, request, jsonify, session
import stripe
import os
from datetime import datetime
import json

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'dev-secret-key')

# 配置Stripe
stripe.api_key = os.getenv('STRIPE_SECRET_KEY')

# 模拟数据库
visa_applications = {}
transactions = {}

@app.route('/')
def index():
    """首页 - 申请表单"""
    return render_template('index.html')

@app.route('/api/apply', methods=['POST'])
def apply_visa():
    """提交签证申请"""
    data = request.json
    
    # 生成申请ID
    application_id = f"VISA-{datetime.now().strftime('%Y%m%d')}-{len(visa_applications)+1:04d}"
    
    # 计算费用
    fee = calculate_visa_fee(
        data['nationality'],
        data['visa_type'],
        data['duration']
    )
    
    # 保存申请
    visa_applications[application_id] = {
        'id': application_id,
        'applicant_name': data['name'],
        'nationality': data['nationality'],
        'visa_type': data['visa_type'],
        'duration': data['duration'],
        'fee': fee,
        'currency': 'USD',
        'status': 'pending_payment',
        'created_at': datetime.now().isoformat()
    }
    
    return jsonify({
        'success': True,
        'application_id': application_id,
        'fee': fee,
        'currency': 'USD'
    })

@app.route('/api/payment', methods=['POST'])
def process_payment():
    """处理支付"""
    data = request.json
    
    application_id = data['application_id']
    
    # 验证申请
    if application_id not in visa_applications:
        return jsonify({
            'success': False,
            'error': '申请不存在'
        })
    
    application = visa_applications[application_id]
    
    try:
        # 创建支付意图
        payment_intent = stripe.PaymentIntent.create(
            amount=int(application['fee'] * 100),  # 转换为美分
            currency=application['currency'],
            payment_method=data['payment_method_id'],
            confirm=True,
            metadata={
                'application_id': application_id,
                'applicant_name': application['applicant_name']
            }
        )
        
        if payment_intent.status == 'succeeded':
            # 更新申请状态
            application['status'] = 'payment_completed'
            application['payment_id'] = payment_intent.id
            
            # 记录交易
            transactions[payment_intent.id] = {
                'transaction_id': payment_intent.id,
                'application_id': application_id,
                'amount': application['fee'],
                'currency': application['currency'],
                'status': 'completed',
                'created_at': datetime.now().isoformat()
            }
            
            return jsonify({
                'success': True,
                'transaction_id': payment_intent.id,
                'application_id': application_id,
                'status': 'completed'
            })
        else:
            return jsonify({
                'success': False,
                'error': '支付未完成'
            })
            
    except stripe.error.CardError as e:
        return jsonify({
            'success': False,
            'error': f'卡错误: {e.user_message}'
        })
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'系统错误: {str(e)}'
        })

@app.route('/api/status/<application_id>')
def get_status(application_id):
    """查询申请状态"""
    if application_id in visa_applications:
        application = visa_applications[application_id]
        return jsonify({
            'success': True,
            'status': application['status'],
            'application_id': application_id,
            'fee': application.get('fee'),
            'currency': application.get('currency')
        })
    else:
        return jsonify({
            'success': False,
            'error': '申请不存在'
        })

def calculate_visa_fee(nationality, visa_type, duration):
    """计算签证费用"""
    base_fee = 100  # 基础费用100美元
    
    # 国籍调整
    if nationality == 'USA':
        fee = base_fee * 1.2
    elif nationality == 'CHN':
        fee = base_fee * 0.9
    else:
        fee = base_fee
    
    # 签证类型调整
    if visa_type == 'tourist':
        fee *= 0.8
    elif visa_type == 'business':
        fee *= 1.5
    
    # 停留时间调整
    if duration > 30:
        fee *= 1.2
    
    return round(fee, 2)

if __name__ == '__main__':
    app.run(debug=True, port=5000)

5.3 前端界面示例

<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电子签证申请与支付</title>
    <script src="https://js.stripe.com/v3/"></script>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        .form-group { margin-bottom: 15px; }
        label { display: block; margin-bottom: 5px; font-weight: bold; }
        input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
        button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
        button:disabled { background: #ccc; }
        .card-element { padding: 10px; border: 1px solid #ddd; border-radius: 4px; margin: 10px 0; }
        .error { color: red; margin: 10px 0; }
        .success { color: green; margin: 10px 0; }
        .hidden { display: none; }
    </style>
</head>
<body>
    <h1>电子签证申请与支付系统</h1>
    
    <!-- 申请表单 -->
    <div id="application-form">
        <h2>填写申请信息</h2>
        <div class="form-group">
            <label>姓名</label>
            <input type="text" id="applicant-name" placeholder="请输入您的姓名">
        </div>
        <div class="form-group">
            <label>国籍</label>
            <select id="nationality">
                <option value="USA">美国</option>
                <option value="CHN">中国</option>
                <option value="GBR">英国</option>
                <option value="JPN">日本</option>
                <option value="OTHER">其他</option>
            </select>
        </div>
        <div class="form-group">
            <label>签证类型</label>
            <select id="visa-type">
                <option value="tourist">旅游签证</option>
                <option value="business">商务签证</option>
                <option value="transit">过境签证</option>
            </select>
        </div>
        <div class="form-group">
            <label>停留天数</label>
            <input type="number" id="duration" value="30" min="1" max="180">
        </div>
        <button onclick="submitApplication()">提交申请</button>
    </div>
    
    <!-- 支付表单 -->
    <div id="payment-form" class="hidden">
        <h2>支付签证费用</h2>
        <p>申请ID: <span id="application-id"></span></p>
        <p>费用: <span id="fee-amount"></span> <span id="fee-currency"></span></p>
        
        <div class="card-element" id="card-element"></div>
        <div id="card-errors" class="error"></div>
        
        <button id="pay-button" onclick="processPayment()">立即支付</button>
        <button onclick="resetForm()">重新申请</button>
    </div>
    
    <!-- 支付结果 -->
    <div id="payment-result" class="hidden">
        <h2>支付结果</h2>
        <div id="result-message"></div>
        <button onclick="resetForm()">返回首页</button>
    </div>

    <script>
        let stripe = Stripe('pk_test_your_publishable_key'); // 替换为你的Stripe公钥
        let elements = stripe.elements();
        let cardElement = elements.create('card', { hidePostalCode: true });
        let currentApplicationId = null;
        
        // 提交申请
        async function submitApplication() {
            const name = document.getElementById('applicant-name').value;
            const nationality = document.getElementById('nationality').value;
            const visaType = document.getElementById('visa-type').value;
            const duration = parseInt(document.getElementById('duration').value);
            
            if (!name) {
                alert('请输入姓名');
                return;
            }
            
            try {
                const response = await fetch('/api/apply', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        name: name,
                        nationality: nationality,
                        visa_type: visaType,
                        duration: duration
                    })
                });
                
                const data = await response.json();
                
                if (data.success) {
                    currentApplicationId = data.application_id;
                    document.getElementById('application-id').textContent = data.application_id;
                    document.getElementById('fee-amount').textContent = data.fee;
                    document.getElementById('fee-currency').textContent = data.currency;
                    
                    // 显示支付表单
                    document.getElementById('application-form').classList.add('hidden');
                    document.getElementById('payment-form').classList.remove('hidden');
                    
                    // 渲染Stripe元素
                    cardElement.mount('#card-element');
                } else {
                    alert('申请失败: ' + data.error);
                }
            } catch (error) {
                alert('网络错误: ' + error.message);
            }
        }
        
        // 处理支付
        async function processPayment() {
            const payButton = document.getElementById('pay-button');
            payButton.disabled = true;
            payButton.textContent = '处理中...';
            
            try {
                // 创建支付方法
                const { paymentMethod, error } = await stripe.createPaymentMethod({
                    type: 'card',
                    card: cardElement
                });
                
                if (error) {
                    document.getElementById('card-errors').textContent = error.message;
                    payButton.disabled = false;
                    payButton.textContent = '立即支付';
                    return;
                }
                
                // 发送支付请求
                const response = await fetch('/api/payment', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        application_id: currentApplicationId,
                        payment_method_id: paymentMethod.id
                    })
                });
                
                const data = await response.json();
                
                // 显示结果
                document.getElementById('payment-form').classList.add('hidden');
                document.getElementById('payment-result').classList.remove('hidden');
                
                const resultDiv = document.getElementById('result-message');
                if (data.success) {
                    resultDiv.innerHTML = `
                        <div class="success">
                            <h3>支付成功!</h3>
                            <p>交易ID: ${data.transaction_id}</p>
                            <p>申请ID: ${data.application_id}</p>
                            <p>您的签证申请已进入处理流程。</p>
                        </div>
                    `;
                } else {
                    resultDiv.innerHTML = `
                        <div class="error">
                            <h3>支付失败</h3>
                            <p>错误信息: ${data.error}</p>
                            <p>请检查支付信息后重试。</p>
                        </div>
                    `;
                }
                
            } catch (error) {
                document.getElementById('card-errors').textContent = '支付处理错误: ' + error.message;
            } finally {
                payButton.disabled = false;
                payButton.textContent = '立即支付';
            }
        }
        
        // 重置表单
        function resetForm() {
            document.getElementById('application-form').classList.remove('hidden');
            document.getElementById('payment-form').classList.add('hidden');
            document.getElementById('payment-result').classList.add('hidden');
            
            // 清空表单
            document.getElementById('applicant-name').value = '';
            document.getElementById('nationality').value = 'USA';
            document.getElementById('visa-type').value = 'tourist';
            document.getElementById('duration').value = '30';
            
            // 清除Stripe元素
            if (cardElement) {
                cardElement.unmount();
                cardElement = elements.create('card', { hidePostalCode: true });
            }
            
            currentApplicationId = null;
        }
    </script>
</body>
</html>

六、性能优化与监控

6.1 性能监控

# 性能监控示例
import time
from functools import wraps
import psutil
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def monitor_performance(func):
    """性能监控装饰器"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        start_memory = psutil.Process().memory_info().rss / 1024 / 1024  # MB
        
        try:
            result = func(*args, **kwargs)
            end_time = time.time()
            end_memory = psutil.Process().memory_info().rss / 1024 / 1024
            
            execution_time = end_time - start_time
            memory_used = end_memory - start_memory
            
            # 记录性能指标
            logger.info(f"函数 {func.__name__} 执行时间: {execution_time:.3f}s, 内存使用: {memory_used:.2f}MB")
            
            # 如果性能异常,发出警告
            if execution_time > 5:  # 超过5秒
                logger.warning(f"函数 {func.__name__} 执行时间过长: {execution_time:.3f}s")
            
            return result
            
        except Exception as e:
            logger.error(f"函数 {func.__name__} 执行出错: {str(e)}")
            raise
    
    return wrapper

# 使用示例
@monitor_performance
def process_large_visa_batch(applications):
    """处理大量签证申请"""
    time.sleep(2)  # 模拟处理时间
    return len(applications)

# 监控系统资源
def monitor_system_resources():
    """监控系统资源使用情况"""
    cpu_percent = psutil.cpu_percent(interval=1)
    memory = psutil.virtual_memory()
    disk = psutil.disk_usage('/')
    
    logger.info(f"CPU使用率: {cpu_percent}%")
    logger.info(f"内存使用: {memory.percent}% ({memory.used/1024/1024:.2f}MB)")
    logger.info(f"磁盘使用: {disk.percent}% ({disk.used/1024/1024/1024:.2f}GB)")
    
    # 如果资源使用过高,发出警告
    if cpu_percent > 80:
        logger.warning(f"CPU使用率过高: {cpu_percent}%")
    if memory.percent > 85:
        logger.warning(f"内存使用率过高: {memory.percent}%")

6.2 缓存策略

# Redis缓存示例
import redis
import json
from datetime import datetime, timedelta

class VisaCache:
    def __init__(self):
        # 连接Redis(实际生产环境需要配置)
        self.redis_client = redis.Redis(
            host='localhost',
            port=6379,
            db=0,
            decode_responses=True
        )
        self.default_ttl = 3600  # 1小时
        
    def cache_visa_fee(self, nationality, visa_type, duration, fee):
        """缓存签证费用计算结果"""
        key = f"visa_fee:{nationality}:{visa_type}:{duration}"
        
        cache_data = {
            'fee': fee,
            'currency': 'USD',
            'cached_at': datetime.now().isoformat(),
            'expires_at': (datetime.now() + timedelta(hours=1)).isoformat()
        }
        
        self.redis_client.setex(
            key,
            self.default_ttl,
            json.dumps(cache_data)
        )
        
        return fee
    
    def get_cached_fee(self, nationality, visa_type, duration):
        """获取缓存的签证费用"""
        key = f"visa_fee:{nationality}:{visa_type}:{duration}"
        
        cached = self.redis_client.get(key)
        if cached:
            cache_data = json.loads(cached)
            
            # 检查是否过期
            expires_at = datetime.fromisoformat(cache_data['expires_at'])
            if datetime.now() < expires_at:
                logger.info(f"从缓存获取费用: {cache_data['fee']}")
                return cache_data['fee']
        
        return None
    
    def cache_exchange_rate(self, base_currency, rates):
        """缓存汇率"""
        key = f"exchange_rate:{base_currency}"
        
        cache_data = {
            'rates': rates,
            'cached_at': datetime.now().isoformat(),
            'expires_at': (datetime.now() + timedelta(hours=1)).isoformat()
        }
        
        self.redis_client.setex(
            key,
            3600,  # 1小时
            json.dumps(cache_data)
        )
    
    def get_cached_exchange_rate(self, base_currency):
        """获取缓存的汇率"""
        key = f"exchange_rate:{base_currency}"
        
        cached = self.redis_client.get(key)
        if cached:
            cache_data = json.loads(cached)
            
            expires_at = datetime.fromisoformat(cache_data['expires_at'])
            if datetime.now() < expires_at:
                return cache_data['rates']
        
        return None

七、总结

电子签证支付系统是一个复杂的多组件系统,涉及前端界面、支付网关集成、安全机制、多币种处理等多个方面。通过本文的实训指导,您应该能够:

  1. 理解系统架构:掌握电子签证支付系统的核心组件和工作流程
  2. 实现支付功能:通过代码示例学习如何集成支付网关
  3. 处理常见问题:了解支付失败、状态同步、多币种处理等问题的解决方案
  4. 确保系统安全:遵循PCI DSS合规要求,实现防欺诈检测
  5. 优化系统性能:通过监控和缓存提升系统响应速度

在实际应用中,建议:

  • 使用专业的支付网关服务(如Stripe、PayPal、支付宝国际版等)
  • 遵循当地法律法规和支付行业标准
  • 定期进行安全审计和性能测试
  • 建立完善的监控和报警机制
  • 提供多语言支持和用户友好的界面

通过持续学习和实践,您可以构建一个稳定、安全、高效的电子签证支付系统,为用户提供优质的签证申请体验。