本页面为机器翻译。英文版本为原文,可能更准确或更及时。 查看英文版

Browser WebSocket

使用原生 WebSocket API 直接从网页浏览器连接到 finlight.me WebSocket API。这非常适合仪表盘、交易终端,以及任何需要实时文章更新且无需服务器端代理的前端应用。


工作原理

  1. 连接wss://wss.finlight.me(增强版)或 wss://wss.finlight.me/raw(原始),并将您的 API 密钥作为查询参数
  2. 订阅:发送一条包含您过滤条件和 clientNonce 的 JSON 消息
  3. 接收:收到一条确认您连接的 admit 消息,随后在文章到达时收到 sendArticle 消息
  4. 保活:每 25 秒发送一次 ping 消息
  5. 断开:调用 ws.close()

连接 URL

  • Name
    增强版
    Type
    wss://wss.finlight.me
    Description

    带完整增强的文章:情绪分析、实体提取、类别和完整内容(取决于您的订阅层级)。

  • Name
    原始
    Type
    wss://wss.finlight.me/raw
    Description

    不含增强的低延迟原始文章。最适合速度优先的用例,即您需要尽可能快地获取文章。

查询参数

  • Name
    apiKey
    Type
    string
    Description

    您的 finlight API 密钥。由于浏览器 WebSocket 无法设置自定义标头,因此用于认证。

  • Name
    takeover
    Type
    string
    Description

    设置为 "true" 可在达到并发连接上限时自动替换最旧的连接。

  • Name
    clientVersion
    Type
    string
    Description

    您客户端应用的可选标识符。例如 "my-dashboard/1.0"


订阅消息

连接打开后,发送一条 JSON 消息以订阅文章。服务器会以一条 admit 消息响应,然后开始推送匹配的文章。

  • Name
    clientNonce
    Type
    string
    Description

    本次订阅请求的唯一标识符(例如 UUID)。服务器会在 admit 响应中回传它。

  • Name
    query
    Type
    string
    Description

    用于查找相关文章的搜索查询。支持高级查询

  • Name
    sources
    Type
    string[]
    Description

    按来源域名过滤。例如 ["www.reuters.com", "www.cnbc.com"]

  • Name
    excludeSources
    Type
    string[]
    Description

    排除特定来源域名。

  • Name
    tickers
    Type
    string[]
    Description

    按股票代码过滤。例如 ["AAPL", "NVDA"](仅限增强版)

  • Name
    countries
    Type
    string[]
    Description

    ISO 3166-1 alpha-2 国家/地区代码过滤。例如 ["US", "DE"](仅限增强版)

  • Name
    language
    Type
    string
    Description

    按语言过滤(ISO 639-1)。默认为 en,仅返回英语并排除其他语言 —— 参见语言与覆盖范围


服务器消息

服务器发送带有 action 字段的 JSON 消息,用于指示消息类型:

  • Name
    admit
    Type
    object
    Description

    在握手成功后发送。包含 leaseIdserverNow(时间戳)和您的 clientNonce

  • Name
    sendArticle
    Type
    object
    Description

    与您订阅匹配的新文章。文章数据位于 data 字段中。

  • Name
    pong
    Type
    object
    Description

    对您 ping 心跳的响应。

  • Name
    preempted
    Type
    object
    Description

    您的连接被另一个会话替换(当另一个客户端以 takeover: true 连接时)。

  • Name
    error
    Type
    object
    Description

    发生了错误。请检查 dataerror 字段以获取详情。


WEBSOCKETBrowser

完整示例

一个最小的、与框架无关的浏览器 WebSocket 客户端,带有自动重连和心跳:

  • 通过查询参数进行认证
  • 连接时发送订阅消息
  • 维持 25 秒的心跳间隔
  • 使用指数退避重连(500 毫秒到 10 秒)
  • 处理所有服务器消息类型

Browser Client

WEBSOCKET
wss://wss.finlight.me
const API_KEY = 'YOUR_API_KEY'
const WSS_URL = 'wss://wss.finlight.me' // Use '/raw' path for raw articles

let ws = null
let pingInterval = null
let reconnectTimeout = null
let reconnectAttempt = 0

function connect(filters = {}) {
  const params = new URLSearchParams({
    apiKey: API_KEY,
    takeover: 'true',
    clientVersion: 'my-app/1.0',
  })
  const url = `${WSS_URL}?${params}`

  ws = new WebSocket(url)

  ws.onopen = () => {
    console.log('Connected')
    reconnectAttempt = 0

    // Send subscription with filters
    ws.send(JSON.stringify({
      clientNonce: crypto.randomUUID(),
      query: filters.query || '',
      language: filters.language || 'en',
      sources: filters.sources || [],
      tickers: filters.tickers || [],
      countries: filters.countries || [],
    }))

    // Start heartbeat
    pingInterval = setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) {
        ws.send(JSON.stringify({
          action: 'ping',
          t: Date.now(),
        }))
      }
    }, 25000)
  }

  ws.onmessage = (event) => {
    const msg = JSON.parse(event.data)

    switch (msg.action) {
      case 'admit':
        console.log('Admitted, lease:', msg.leaseId)
        break
      case 'sendArticle':
        console.log('Article:', msg.data.title)
        // Handle the article here
        break
      case 'pong':
        break // Heartbeat OK
      case 'preempted':
        console.warn('Connection replaced')
        break
      case 'error':
        console.error('Server error:', msg.data || msg.error)
        break
    }
  }

  ws.onclose = (event) => {
    clearInterval(pingInterval)

    // Don't reconnect on policy violations
    if (event.code === 1008 || event.code === 4002) {
      console.error('Connection blocked')
      return
    }

    // Exponential backoff reconnect
    const delay = Math.min(500 * 2 ** reconnectAttempt, 10000)
    reconnectAttempt++
    console.log(`Reconnecting in ${delay}ms...`)
    reconnectTimeout = setTimeout(() => connect(filters), delay)
  }

  ws.onerror = () => console.error('WebSocket error')
}

function disconnect() {
  clearInterval(pingInterval)
  clearTimeout(reconnectTimeout)
  if (ws) ws.close(1000)
}

// Usage
connect({ query: 'Nvidia', language: 'en', countries: ['US'] })

admit Response

{
  "action": "admit",
  "leaseId": "a1b2c3d4-e5f6-4789-abcd-ef0123456789",
  "serverNow": 1708185600000,
  "clientNonce": "your-uuid-here"
}

sendArticle Response

{
  "action": "sendArticle",
  "data": {
    "link": "https://www.reuters.com/technology/nvidia-2026-02-17",
    "source": "www.reuters.com",
    "title": "Nvidia Reports Record Revenue",
    "summary": "Nvidia announced record quarterly revenue...",
    "publishDate": "2026-02-17T10:30:00Z",
    "language": "en",
    "sentiment": "positive",
    "confidence": 0.92,
    "countries": ["US"],
    "categories": ["markets", "technology"],
    "companies": [
      {
        "name": "NVIDIA Corporation",
        "ticker": "NVDA",
        "country": "US"
      }
    ]
  }
}

增强版与原始对比

功能增强版 (/)原始 (/raw)
情绪分析
实体提取(公司)是(取决于层级)
类别
完整内容是(取决于层级)
延迟标准最低
过滤器:tickers
过滤器:countries
过滤器:querysourceslanguage

接下来做什么?