首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >使用 Fetch API 处理AI流式接口,实现在Web开发中前后端的数据交互与显示

使用 Fetch API 处理AI流式接口,实现在Web开发中前后端的数据交互与显示

作者头像
程序猿的栖息地
发布2025-08-01 14:14:44
发布2025-08-01 14:14:44
6390
举报

使用 Fetch API 实现现代前端数据交互

引言

在当今的 Web 开发中,前端与后端的数据交互是构建动态应用的核心。传统的页面刷新方式已经无法满足用户对流畅体验的需求,而 Fetch API 的出现为 JavaScript 带来了全新的生命力。本文将深入探讨 Fetch API 的工作原理、使用方法以及如何利用它与大模型服务(如 DeepSeek)进行交互。

一、Fetch API 概述

Fetch API 是现代浏览器提供的一个用于发起网络请求的接口,它比传统的 XMLHttpRequest 更加强大、灵活且易于使用。Fetch 基于 Promise 设计,使得异步请求的处理更加优雅。

1.1 Fetch 的基本语法

javascript

代码语言:javascript
复制
fetch(url, options)
  .then(response => {
    // 处理响应
  })
  .catch(error => {
    // 处理错误
  });

或者使用 async/await 语法:

javascript

代码语言:javascript
复制
async function fetchData() {
  try {
    const response = await fetch(url, options);
    const data = await response.json();
    // 处理数据
  } catch (error) {
    // 处理错误
  }
}
1.2 Fetch 与传统 AJAX 的比较

特性

Fetch API

XMLHttpRequest

语法

基于 Promise,更简洁

回调函数,较复杂

请求/响应对象

标准化

非标准化

默认携带 Cookie

不携带

携带

超时控制

需要额外实现

原生支持

取消请求

使用 AbortController

原生支持

进度事件

有限支持

完整支持

二、Fetch API 的详细使用

2.1 发起 GET 请求

GET 请求是最常见的请求类型,用于从服务器获取数据:

javascript

代码语言:javascript
复制
fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    console.log('Success:', data);
    // 更新DOM
    document.getElementById('content').innerHTML = 
      data.map(item => `<li>${item.name}</li>`).join('');
  })
  .catch(error => {
    console.error('Error:', error);
  });
2.2 发起 POST 请求

POST 请求用于向服务器发送数据,如提交表单或调用 API:

javascript

代码语言:javascript
复制
const userData = {
  username: 'example',
  email: 'example@example.com'
};

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your_token_here'
  },
  body: JSON.stringify(userData)
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));
2.3 处理不同的响应类型

Fetch API 可以处理多种响应格式:

javascript

代码语言:javascript
复制
// 处理JSON响应
fetch('/api/data.json')
  .then(response => response.json())
  .then(data => console.log(data));

// 处理文本响应
fetch('/api/data.txt')
  .then(response => response.text())
  .then(text => console.log(text));

// 处理Blob响应(如图片)
fetch('/image.png')
  .then(response => response.blob())
  .then(blob => {
    const objectURL = URL.createObjectURL(blob);
    document.getElementById('image').src = objectURL;
  });
2.4 错误处理

正确的错误处理对于健壮的应用至关重要:

javascript

代码语言:javascript
复制
async function fetchWithErrorHandling() {
  try {
    const response = await fetch('https://api.example.com/data');

    if (!response.ok) {
      // 根据HTTP状态码抛出不同的错误
      if (response.status === 404) {
        throw new Error('Resource not found');
      } else if (response.status === 401) {
        throw new Error('Unauthorized');
      } else {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
    }

    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Fetch error:', error);
    // 显示用户友好的错误信息
    displayErrorMessage(error.message);
  }
}

function displayErrorMessage(message) {
  const errorElement = document.getElementById('error-message');
  errorElement.textContent = message;
  errorElement.style.display = 'block';
}

三、高级 Fetch 用法

3.1 设置请求超时

Fetch API 本身不支持超时设置,但可以通过 AbortController 实现:

javascript

代码语言:javascript
复制
const controller = new AbortController();
const signal = controller.signal;

// 设置5秒超时
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://api.example.com/data', { signal })
  .then(response => response.json())
  .then(data => {
    clearTimeout(timeoutId);
    console.log(data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Request timed out');
    } else {
      console.error('Other error:', error);
    }
  });
3.2 上传文件

使用 Fetch 上传文件:

javascript

代码语言:javascript
复制
const formData = new FormData();
const fileInput = document.querySelector('input[type="file"]');

formData.append('file', fileInput.files[0]);
formData.append('username', 'exampleUser');

fetch('https://api.example.com/upload', {
  method: 'POST',
  body: formData
  // 注意:不要手动设置Content-Type头,浏览器会自动设置正确的boundary
})
.then(response => response.json())
.then(data => console.log('Upload success:', data))
.catch(error => console.error('Upload error:', error));
3.3 请求取消

使用 AbortController 取消正在进行的请求:

javascript

代码语言:javascript
复制
const controller = new AbortController();

// 开始请求
fetch('https://api.example.com/data', {
  signal: controller.signal
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
  if (error.name === 'AbortError') {
    console.log('Request was aborted');
  } else {
    console.error('Error:', error);
  }
});

// 在某个事件中取消请求
document.getElementById('cancel-button').addEventListener('click', () => {
  controller.abort();
});
3.4 并发请求

使用 Promise.all 处理多个并发请求:

javascript

代码语言:javascript
复制
async function fetchMultipleResources() {
  try {
    const [usersResponse, postsResponse] = await Promise.all([
      fetch('https://api.example.com/users'),
      fetch('https://api.example.com/posts')
    ]);

    if (!usersResponse.ok || !postsResponse.ok) {
      throw new Error('One or more requests failed');
    }

    const users = await usersResponse.json();
    const posts = await postsResponse.json();

    console.log('Users:', users);
    console.log('Posts:', posts);

    // 合并数据并更新UI
    displayCombinedData(users, posts);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

function displayCombinedData(users, posts) {
  // 实现数据合并和显示逻辑
}

四、Fetch 与大模型服务的集成

4.1 调用 DeepSeek 等大模型 API

现代前端可以直接调用大模型服务的 API,实现智能功能:

javascript

代码语言:javascript
复制
async function queryDeepSeek(prompt) {
  const apiKey = 'your_api_key_here'; // 实际应用中应从安全的地方获取

  try {
    const response = await fetch('https://api.deepseek.com/chat/completions', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`
      },
      body: JSON.stringify({
        model: 'deepseek-chat',
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.7,
        max_tokens: 1000
      })
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.error?.message || 'API request failed');
    }

    const data = await response.json();
    return data.choices[0].message.content;
  } catch (error) {
    console.error('API call failed:', error);
    throw error;
  }
}

// 使用示例
document.getElementById('ask-button').addEventListener('click', async () => {
  const question = document.getElementById('question-input').value;
  const answerElement = document.getElementById('answer');

  answerElement.textContent = '思考中...';

  try {
    const answer = await queryDeepSeek(question);
    answerElement.textContent = answer;
  } catch (error) {
    answerElement.textContent = `出错: ${error.message}`;
  }
});
4.2 流式处理大模型响应

对于长文本生成,可以使用流式处理来改善用户体验:

javascript

代码语言:javascript
复制
async function streamDeepSeekResponse(prompt) {
  const apiKey = 'your_api_key_here';
  const response = await fetch('https://api.deepseek.com/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: 'deepseek-chat',
      messages: [{ role: 'user', content: prompt }],
      temperature: 0.7,
      max_tokens: 1000,
      stream: true // 启用流式响应
    })
  });

  if (!response.ok) {
    throw new Error(`API request failed with status ${response.status}`);
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let result = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value, { stream: true });
    const lines = chunk.split('\n').filter(line => line.trim() !== '');

    for (const line of lines) {
      const message = line.replace(/^data: /, '');
      if (message === '[DONE]') {
        return result;
      }

      try {
        const parsed = JSON.parse(message);
        const content = parsed.choices[0]?.delta?.content || '';
        result += content;
        document.getElementById('stream-output').textContent += content;
      } catch (error) {
        console.error('Error parsing message:', error);
      }
    }
  }

  return result;
}
4.3 前端缓存策略

为了提高性能并减少 API 调用,可以实现简单的前端缓存:

javascript

代码语言:javascript
复制
const apiCache = new Map();

async function cachedFetch(url, options = {}) {
  const cacheKey = `${url}:${JSON.stringify(options)}`;

  // 检查缓存
  if (apiCache.has(cacheKey)) {
    const { data, timestamp } = apiCache.get(cacheKey);
    // 5分钟缓存有效期
    if (Date.now() - timestamp < 5 * 60 * 1000) {
      return data;
    }
  }

  // 发起新请求
  const response = await fetch(url, options);
  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }

  const data = await response.json();

  // 更新缓存
  apiCache.set(cacheKey, {
    data,
    timestamp: Date.now()
  });

  return data;
}

// 使用示例
document.getElementById('load-data').addEventListener('click', async () => {
  try {
    const data = await cachedFetch('https://api.example.com/data');
    displayData(data);
  } catch (error) {
    console.error('Error:', error);
  }
});

五、Fetch 在实际应用中的最佳实践

5.1 封装通用请求函数

在实际项目中,建议封装一个通用的请求函数:

javascript

代码语言:javascript
复制
class ApiClient {
  constructor(baseUrl, defaultHeaders = {}) {
    this.baseUrl = baseUrl;
    this.defaultHeaders = {
      'Content-Type': 'application/json',
      ...defaultHeaders
    };
  }

  async request(endpoint, method = 'GET', body = null, customHeaders = {}) {
    const url = `${this.baseUrl}${endpoint}`;
    const headers = { ...this.defaultHeaders, ...customHeaders };

    const config = {
      method,
      headers,
      credentials: 'include' // 如果需要发送cookie
    };

    if (body) {
      config.body = typeof body === 'object' ? JSON.stringify(body) : body;
    }

    try {
      const response = await fetch(url, config);

      if (!response.ok) {
        const errorData = await this.parseResponse(response);
        throw new HttpError(response.status, errorData.message || 'Request failed');
      }

      return await this.parseResponse(response);
    } catch (error) {
      console.error(`API request failed: ${error.message}`);
      throw error;
    }
  }

  async parseResponse(response) {
    const contentType = response.headers.get('content-type');
    if (contentType && contentType.includes('application/json')) {
      return await response.json();
    }
    return await response.text();
  }

  get(endpoint, headers) {
    return this.request(endpoint, 'GET', null, headers);
  }

  post(endpoint, body, headers) {
    return this.request(endpoint, 'POST', body, headers);
  }

  put(endpoint, body, headers) {
    return this.request(endpoint, 'PUT', body, headers);
  }

  delete(endpoint, headers) {
    return this.request(endpoint, 'DELETE', null, headers);
  }
}

class HttpError extends Error {
  constructor(status, message) {
    super(message);
    this.status = status;
    this.name = 'HttpError';
  }
}

// 使用示例
const api = new ApiClient('https://api.example.com', {
  'Authorization': 'Bearer your_token_here'
});

async function loadUserData(userId) {
  try {
    const user = await api.get(`/users/${userId}`);
    const posts = await api.get(`/users/${userId}/posts`);
    return { user, posts };
  } catch (error) {
    if (error.status === 404) {
      console.log('User not found');
    } else {
      console.error('Error loading user data:', error);
    }
    throw error;
  }
}
5.2 处理身份验证

对于需要身份验证的 API,可以这样处理:

javascript

代码语言:javascript
复制
let authToken = null;

async function login(username, password) {
  try {
    const response = await fetch('/api/auth/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ username, password })
    });

    if (!response.ok) {
      throw new Error('Login failed');
    }

    const data = await response.json();
    authToken = data.token;
    localStorage.setItem('authToken', data.token);
    return data.user;
  } catch (error) {
    console.error('Login error:', error);
    throw error;
  }
}

async function fetchWithAuth(url, options = {}) {
  if (!authToken) {
    authToken = localStorage.getItem('authToken');
    if (!authToken) {
      throw new Error('Not authenticated');
    }
  }

  const headers = {
    ...options.headers,
    'Authorization': `Bearer ${authToken}`
  };

  return fetch(url, { ...options, headers });
}

// 使用示例
async function loadProtectedData() {
  try {
    const response = await fetchWithAuth('/api/protected/data');
    const data = await response.json();
    console.log('Protected data:', data);
    return data;
  } catch (error) {
    console.error('Error loading protected data:', error);
    if (error.message === 'Not authenticated') {
      // 重定向到登录页面
      window.location.href = '/login';
    }
    throw error;
  }
}
5.3 性能优化技巧
  1. 批量请求:合并多个小请求为一个批量请求
  2. 请求去重:避免同时发送相同的请求
  3. 请求优先级:关键请求优先发送
  4. 预加载:预测用户行为提前加载数据

javascript

代码语言:javascript
复制
class RequestScheduler {
  constructor(maxConcurrent = 5) {
    this.maxConcurrent = maxConcurrent;
    this.queue = [];
    this.activeCount = 0;
  }

  enqueue(requestFn, priority = 0) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject, priority });
      this.queue.sort((a, b) => b.priority - a.priority);
      this.processQueue();
    });
  }

  async processQueue() {
    if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) {
      return;
    }

    this.activeCount++;
    const { requestFn, resolve, reject } = this.queue.shift();

    try {
      const result = await requestFn();
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.activeCount--;
      this.processQueue();
    }
  }
}

// 使用示例
const scheduler = new RequestScheduler(3);

async function fetchWithPriority(url, priority = 0) {
  return scheduler.enqueue(() => fetch(url).then(r => r.json()), priority);
}

// 高优先级请求
fetchWithPriority('/api/critical-data', 10)
  .then(data => console.log('Critical data:', data));

// 普通优先级请求
fetchWithPriority('/api/normal-data')
  .then(data => console.log('Normal data:', data));

六、Fetch 的现代替代方案

虽然 Fetch API 功能强大,但在某些场景下可以考虑以下替代方案:

6.1 Axios

Axios 是一个流行的 HTTP 客户端库,提供了一些额外功能:

javascript

代码语言:javascript
复制
import axios from 'axios';

// 简单GET请求
axios.get('/api/data')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

// 带配置的POST请求
axios.post('/api/users', {
  name: 'John Doe',
  email: 'john@example.com'
}, {
  headers: {
    'Authorization': 'Bearer token'
  },
  timeout: 5000
})
.then(response => console.log(response.data));
6.2 React Query (TanStack Query)

对于 React 应用,React Query 提供了强大的数据获取和缓存功能:

javascript

代码语言:javascript
复制
import { useQuery } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const { data, error, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => 
      fetch(`/api/users/${userId}`)
        .then(res => res.json()),
    staleTime: 5 * 60 * 1000 // 5分钟缓存
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>Email: {data.email}</p>
    </div>
  );
}
6.3 SWR (Stale-While-Revalidate)

另一个 React 数据获取库,由 Vercel 开发:

javascript

代码语言:javascript
复制
import useSWR from 'swr';

const fetcher = (...args) => fetch(...args).then(res => res.json());

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher, {
    refreshInterval: 30000 // 每30秒刷新
  });

  if (error) return <div>Failed to load</div>;
  if (!data) return <div>Loading...</div>;

  return <div>Hello {data.name}!</div>;
}

七、未来展望:Fetch 与 AI 时代的结合

随着大模型技术的发展,前端与 AI 的交互变得越来越普遍。Fetch API 将成为连接前端与大模型服务的重要桥梁:

  1. 实时 AI 交互:通过流式 Fetch 实现与大模型的实时对话
  2. 边缘计算:将部分 AI 推理工作下放到边缘节点,减少延迟
  3. 个性化体验:根据用户行为数据实时调整 AI 响应
  4. 混合架构:结合本地小型模型和云端大模型,平衡性能与效果

javascript

代码语言:javascript
复制
// 未来可能的AI增强Fetch示例
async function aiEnhancedFetch(resource, init) {
  // 分析请求上下文
  const context = analyzeRequestContext(resource, init);

  // 根据上下文决定是否使用本地模型
  if (shouldUseLocalModel(context)) {
    const localResult = await runLocalAI(init.body);
    return new Response(JSON.stringify(localResult));
  }

  // 否则调用云端大模型
  const response = await fetch(resource, init);

  // 后处理:可能缓存结果或生成摘要
  return postProcessResponse(response);
}

结语

Fetch API 是现代 Web 开发的基石之一,它简化了前端与后端的通信,为构建动态、响应式的 Web 应用提供了强大支持。随着 AI 技术的普及,Fetch 将成为连接前端智能与云端大模型的关键技术。掌握 Fetch 的高级用法和最佳实践,将帮助开发者构建更高效、更智能的 Web 应用。

无论是传统的 REST API 交互,还是新兴的大模型服务调用,Fetch API 都将继续发挥重要作用。希望本文能够帮助读者深入理解 Fetch 的工作原理,并在实际项目中灵活运用这些技术。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿的栖息地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用 Fetch API 实现现代前端数据交互
    • 引言
    • 一、Fetch API 概述
      • 1.1 Fetch 的基本语法
      • 1.2 Fetch 与传统 AJAX 的比较
    • 二、Fetch API 的详细使用
      • 2.1 发起 GET 请求
      • 2.2 发起 POST 请求
      • 2.3 处理不同的响应类型
      • 2.4 错误处理
    • 三、高级 Fetch 用法
      • 3.1 设置请求超时
      • 3.2 上传文件
      • 3.3 请求取消
      • 3.4 并发请求
    • 四、Fetch 与大模型服务的集成
      • 4.1 调用 DeepSeek 等大模型 API
      • 4.2 流式处理大模型响应
      • 4.3 前端缓存策略
    • 五、Fetch 在实际应用中的最佳实践
      • 5.1 封装通用请求函数
      • 5.2 处理身份验证
      • 5.3 性能优化技巧
    • 六、Fetch 的现代替代方案
      • 6.1 Axios
      • 6.2 React Query (TanStack Query)
      • 6.3 SWR (Stale-While-Revalidate)
    • 七、未来展望:Fetch 与 AI 时代的结合
    • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档