QuotaExceededError The quota has been exceeded

当在iOS 10及以下版本的Safari无痕浏览模式中使用localStorage或sessionStorage时,可能会遇到QuotaExceededError。为解决此问题,可以检测浏览器是否支持这些存储并提示用户切换模式,或者在不支持时默认切换到cookie存储。由于cookie存储空间有限,建议只用于少量数据。本文提供了检测和切换到cookie的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(一)前言
我首先描述下,这种报错出现的场景

  1. ios <= 10 真机 Safari 的无痕浏览模式
  2. 使用localStorage or sessionStorage 的 setItem

当然,问题肯定社区有解决方案,以下链接可以满足你想要的答案
问题链接1
问题链接2
问题链接3

(二)解决过程

如果你看完,那么问题可以总结为,两个方向

  1. 是我们h5站点增加检测是否支持,并提示用户切换模式
  2. 我们在不支持情况,默认切到cookie

当然因为cookie本身储存空间不大,所以建议如果本地存储大量数据,不建议用2,以下为2中支持提供代码

检测是否支持

function isStorageNameSupported(storage) {
   
   
    var testKey = 'test';
    try {
   
   
        storage.setItem(testKey, '1');
        storage.removeItem(testKey);
        return storage in win && win[storage];
    } catch (error) {
   
   
        return false;
    }
}

默认切换到cookie

因为cookie需要字符串处理,所以安装一个包
js-cookie

首先实现一个storageHelper类,提供切换

import Cookies from 'js-cookie';
<think>我们遇到了一个错误:`AttributeError: 'Object' object has no attribute 'resource'`。这个错误通常发生在使用`vt-py`库时,尝试访问一个不存在的属性`resource`。 在之前的代码中,我们使用了以下步骤: 1. 上传文件并开始分析,获取分析对象(`analysis`)。 2. 使用`client.get_object(f"/analyses/{analysis.id}")`获取分析状态。 3. 当分析完成时,我们尝试通过`analysis.resource`获取文件的资源ID(即文件的SHA256、MD5或SHA1),然后使用`client.get_object(f"/files/{analysis.resource}")`来获取文件报告。 但是,根据`vt-py`库的文档,分析对象(`analysis`)并没有一个名为`resource`的属性。实际上,分析对象有一个`id`属性,但我们需要的是被分析文件的资源ID(通常是文件的哈希值)。在分析完成后的报告中,我们可以通过分析对象的`attributes`获取文件的资源ID。 正确的做法是: - 当分析完成时,分析对象的`attributes`中包含一个`resource`字段,该字段就是文件的哈希值(SHA256)。我们可以通过`analysis.attributes['resource']`来获取。 修改后的代码: ```python report = client.get_object(f"/files/{analysis.attributes['resource']}") ``` 但是,请注意:在`vt-py`库中,分析对象(`analysis`)还有一个`relationships`属性,其中包含一个`resource`关系,指向被分析的文件。因此,也可以这样获取: ```python file_hash = analysis.relationships['resource']['data']['id'] ``` 然而,更简单的方式是直接使用`analysis.attributes['resource']`。 因此,我们需要修改`analyze_file`函数中获取报告的部分: ```python # 等待分析完成 print(f"等待 {file_name} 分析完成...", end="", flush=True) while True: analysis = client.get_object(f"/analyses/{analysis.id}") if analysis.status == "completed": print("完成") break print(".", end="", flush=True) time.sleep(30) # 遵守API速率限制 # 从分析对象中获取文件的资源ID(即SHA256) file_hash = analysis.attributes['resource'] # 获取完整报告 report = client.get_object(f"/files/{file_hash}") ``` 这样,我们就避免了直接访问`analysis.resource`,而是通过`analysis.attributes['resource']`获取文件的哈希值。 完整修改后的代码: ```python import vt import time import os def analyze_file(api_key, file_path): """上传文件到VirusTotal并获取分析报告""" client = vt.Client(api_key) try: # 检查文件是否存在 if not os.path.exists(file_path): print(f"错误: 文件不存在 - {file_path}") return None # 上传文件 file_name = os.path.basename(file_path) print(f"正在上传 {file_name}...") with open(file_path, "rb") as f: analysis = client.scan_file(f, wait_for_completion=False) # 等待分析完成 print(f"等待 {file_name} 分析完成...", end="", flush=True) while True: analysis = client.get_object(f"/analyses/{analysis.id}") if analysis.status == "completed": print("完成") break print(".", end="", flush=True) time.sleep(30) # 遵守API速率限制 # 从分析对象中获取文件的资源ID(即SHA256) file_hash = analysis.attributes['resource'] # 获取完整报告 report = client.get_object(f"/files/{file_hash}") return report except vt.APIError as e: print(f"\nAPI错误: {e}") if "QuotaExceededError" in str(e): print("API配额已用尽,请稍后再试") return None except Exception as e: print(f"\n发生错误: {e}") return None finally: client.close() def print_report(report, file_name): """打印分析报告""" if not report: return stats = report.last_analysis_stats print(f"\n{'='*40}") print(f"文件: {file_name}") print(f"检测结果: {stats['malicious']}个安全厂商标记为恶意") print(f"安全厂商总数: {sum(stats.values())}") print(f"安全评级: {get_verdict(stats)}") # 显示恶意引擎详情 if stats['malicious'] > 0: print("\n恶意检测详情:") for engine, result in report.last_analysis_results.items(): if result['category'] == 'malicious': print(f" ▸ {engine}: {result['result']}") def get_verdict(stats): """生成安全评级""" malicious = stats['malicious'] if malicious == 0: return "安全 ✅" elif malicious <= 3: return "低风险 ⚠️" elif malicious <= 10: return "中等风险 ⚠️⚠️" else: return "高风险 ❗❗❗" if __name__ == "__main__": # 配置信息 API_KEY = "b3beefb3ff7eb6966e25a46384116657d53647cca6a5a0e0e06f514ffe1d3f55" FILES = [ r"C:\Users\hiking\Desktop\share1\static.exe", r"C:\Users\hiking\Desktop\share1\dynamic.exe" ] # 分析每个文件 for file_path in FILES: file_name = os.path.basename(file_path) report = analyze_file(API_KEY, file_path) print_report(report, file_name) ``` 这样修改后,应该可以解决`AttributeError: 'Object' object has no attribute 'resource'`错误。 另外,请注意,我们添加了更全面的异常处理,以捕获其他可能的错误。 §§相关问题§§ 1. 如何获取VirusTotal分析报告中的其他信息(如行为分析、网络流量等)? 2. 当API返回错误`QuotaExceededError`时,如何自动等待并重试? 3. 如何批量上传多个文件并同时处理分析报告? 4. 如何将分析结果保存为JSON文件以便后续分析?</think># 解决 VirusTotal API 中的 AttributeError: 'Object' object has no attribute 'resource' 错误 当使用 Python 调用 VirusTotal API 时遇到 `AttributeError: 'Object' object has no attribute 'resource'` 错误,这通常是由于 API 响应格式变化或对象属性访问方式不正确导致的。下面我将详细解释问题原因并提供解决方案。 ## 问题原因分析 这个错误表明您尝试访问的 `resource` 属性在返回的 API 响应对象中不存在。可能的原因包括: 1. **API 响应格式变化**:VirusTotal API 可能更新了响应格式 2. **对象类型错误**:返回的对象不是预期的分析结果对象 3. **属性访问方式错误**:需要访问不同的属性路径来获取资源标识符 4. **分析未完成**:尝试在分析完成前访问结果属性 ## 解决方案 ### 方法 1:使用正确的属性路径 根据 VirusTotal API 最新文档,分析结果中的资源标识符应通过 `attributes` 字典访问: ```python def get_analysis_report(analysis_id): """获取分析报告,返回检测统计信息""" report_url = f"{BASE_URL}/analyses/{analysis_id}" while True: response = requests.get(report_url, headers=HEADERS) if response.status_code == 200: report = response.json() status = report['data']['attributes']['status'] if status == 'completed': # 正确访问资源标识符的方式 file_hash = report['data']['attributes']['resource'] # 使用文件哈希获取完整报告 file_report_url = f"{BASE_URL}/files/{file_hash}" file_response = requests.get(file_report_url, headers=HEADERS) file_report = file_response.json() stats = file_report['data']['attributes']['last_analysis_stats'] return stats # ... 其他状态处理 ... ``` ### 方法 2:使用官方 Python SDK VirusTotal 提供了官方的 Python SDK `vt-py`,它封装了 API 调用并提供了更稳定的接口: ```python import vt import os def analyze_with_sdk(file_path, api_key): """使用官方SDK分析文件""" client = vt.Client(api_key) try: # 上传文件 with open(file_path, "rb") as f: analysis = client.scan_file(f, wait_for_completion=True) # 获取文件哈希 file_hash = analysis.resource # SDK中resource属性可用 # 获取完整报告 file_report = client.get_object(f"/files/{file_hash}") stats = file_report.last_analysis_stats return stats except vt.APIError as e: print(f"API错误: {e}") return None finally: client.close() ``` ### 方法 3:处理未完成的分析状态 确保只在分析完成时访问资源属性: ```python def get_analysis_report(analysis_id): report_url = f"{BASE_URL}/analyses/{analysis_id}" while True: response = requests.get(report_url, headers=HEADERS) if response.status_code == 200: report = response.json() attributes = report['data']['attributes'] # 检查分析状态 if attributes['status'] == 'completed': # 安全访问资源标识符 if 'resource' in attributes: file_hash = attributes['resource'] # 备选属性访问方式 elif 'results' in attributes and 'resource' in attributes['results']: file_hash = attributes['results']['resource'] else: print("无法找到资源标识符") return None # 获取完整报告... return stats # 其他状态处理... ``` ## 完整解决方案 以下是结合所有修复的完整代码示例: ```python import requests import time import os from dotenv import load_dotenv # 加载环境变量 load_dotenv() API_KEY = os.getenv("VT_API_KEY", "your_api_key_here") BASE_URL = "https://www.virustotal.com/api/v3" HEADERS = {"x-apikey": API_KEY, "Accept": "application/json"} def upload_file(file_path): """上传文件到VirusTotal并返回分析ID""" upload_url = f"{BASE_URL}/files" try: with open(file_path, 'rb') as file: files = {'file': (os.path.basename(file_path), file)} response = requests.post(upload_url, headers=HEADERS, files=files) response.raise_for_status() return response.json()['data']['id'] except Exception as e: print(f"上传失败: {e}") return None def get_analysis_report(analysis_id): """获取分析报告,返回检测统计信息""" report_url = f"{BASE_URL}/analyses/{analysis_id}" attempts = 0 max_attempts = 20 # 最大尝试次数 (约10分钟) while attempts < max_attempts: try: response = requests.get(report_url, headers=HEADERS) response.raise_for_status() report = response.json() attributes = report['data']['attributes'] status = attributes['status'] if status == 'completed': # 安全获取资源标识符 file_hash = attributes.get('resource') if not file_hash: # 备选获取方式 file_hash = attributes.get('results', {}).get('resource') if not file_hash: print("错误: 无法获取文件哈希") return None # 获取完整文件报告 file_report_url = f"{BASE_URL}/files/{file_hash}" file_response = requests.get(file_report_url, headers=HEADERS) file_response.raise_for_status() file_report = file_response.json() stats = file_report['data']['attributes']['last_analysis_stats'] return stats elif status == 'queued': print(f"分析排队中... ({attempts+1}/{max_attempts})") time.sleep(30) attempts += 1 else: print(f"未知分析状态: {status}") return None except requests.exceptions.RequestException as e: print(f"请求错误: {e}") return None def analyze_sample(file_path): """分析样本并打印结果""" print(f"\n分析样本: {os.path.basename(file_path)}") # 上传文件 analysis_id = upload_file(file_path) if not analysis_id: print("上传失败,跳过分析") return print(f"分析ID: {analysis_id}") print("分析进行中,请稍候...") # 获取分析报告 stats = get_analysis_report(analysis_id) if stats: malicious = stats.get('malicious', 0) undetected = stats.get('undetected', 0) suspicious = stats.get('suspicious', 0) total = malicious + undetected + suspicious print("\n检测结果:") print(f"安全厂商总数: {total}") print(f"恶意报警: {malicious}") print(f"可疑报警: {suspicious}") print(f"未检测数量: {undetected}") print(f"检测率: {(malicious + suspicious)}/{total} ({(malicious + suspicious)/total*100:.1f}%)") else: print("无法获取分析结果") if __name__ == "__main__": # 样本文件路径 SAMPLE1_PATH = r"C:\Users\hiking\Desktop\share1\dynamic.exe" SAMPLE2_PATH = r"C:\Users\hiking\Desktop\share1\static.exe" analyze_sample(SAMPLE1_PATH) analyze_sample(SAMPLE2_PATH) ``` ## 关键修复点 1. **属性安全访问**: ```python # 使用get()方法避免属性不存在时报错 file_hash = attributes.get('resource') # 备选访问路径 file_hash = attributes.get('results', {}).get('resource') ``` 2. **错误处理增强**: ```python try: response.raise_for_status() # ... except requests.exceptions.RequestException as e: print(f"请求错误: {e}") return None ``` 3. **完整报告获取**: ```python # 获取完整文件报告而非分析报告 file_report_url = f"{BASE_URL}/files/{file_hash}" file_response = requests.get(file_report_url, headers=HEADERS) ``` 4. **循环退出机制**: ```python attempts = 0 max_attempts = 20 # 最大尝试次数 while attempts < max_attempts: # ... attempts += 1 ``` ## 最佳实践建议 1. **使用官方SDK**:`vt-py`库封装了API调用细节,减少底层错误 2. **环境变量管理**:始终通过`.env`文件管理API密钥 3. **速率限制处理**:免费API限制4请求/分钟,需添加适当延迟 ```python time.sleep(15) # 每15秒一个请求 ``` 4. **大文件处理**:超过32MB的文件需要分块上传[^1] [^1]: VirusTotal API 文档规定文件大小上限为32MB,更大文件需使用特殊上传方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值