> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/lian-wang/network-connections.md).

# 网络连接

如何让你的场景与外部服务器和 API 通信。

你的场景可以利用暴露 API 的外部服务，你可以用它来获取最新价格数据、天气数据或 API 暴露的任何其他信息。

你也可以搭建自己的外部服务器来辅助你的场景，并用于在玩家之间同步数据。这可以通过暴露 REST API 的服务器来实现，也可以通过使用 WebSockets 的服务器来实现。

## 调用 REST API

你的场景代码可以发送调用 REST API 的请求来获取数据。

由于服务器可能需要一些时间才能发送响应，你必须将此命令作为一个 [异步函数](/creator/content-creator-zh/chang-jing-sdk7/bian-cheng-mo-shi/async-functions.md)，使用 `executeTask()`.

```ts
executeTask(async () => {
	try {
		let response = await fetch(callUrl)
		let json = await response.json()
		console.log(json)
	} catch {
		console.log('无法访问 URL')
	}
})
```

fetch 命令还可以包含第二个可选参数，它会将标头、HTTP 方法和 HTTP 正文打包到一个对象中。

* **url**：发送请求的地址
* **init**：一个 `RequestInit` 可能包含以下内容的对象：
  * **method** ：要使用的 HTTP 方法（GET、POST、DELETE 等）
  * **body**：请求正文的内容。它必须以字符串化的 JSON 对象发送。
  * **headers**：要包含在请求中的附加标头。
  * **redirect**：重定向策略（'follow' | 'error' | 'manual'）
  * **timeout**：在请求失败前等待响应的时长。默认 30000 毫秒（30 秒）。

```ts
executeTask(async () => {
	try {
		let response = await fetch(callUrl, {
			headers: { 'Content-Type': 'application/json' },
			method: 'POST',
			body: JSON.stringify(myBody),
		})
		let json = await response.json()
		console.log(json)
	} catch {
		console.log('无法访问 URL')
	}
})
```

fetch 命令返回一个 `response` 包含以下数据的对象：

* `headers`：一个 `ReadOnlyHeaders` 对象。调用 `get()` 方法以获取特定标头，或使用 `has()` 方法检查某个标头是否存在。
* `ok`：布尔值
* `redirected`：布尔值
* `status`：状态代码数字
* `statusText`：状态代码的文本
* `type`：将具有以下值之一： *basic*, *cors*, *default*, *error*, *opaque*, *opaqueredirect*
* `url`：已发送的 URL
* `json()`：以 JSON 格式获取正文。
* `text()`：以文本格式获取正文。

{% hint style="warning" %}
**📔 注意**: `json()` 和 `text()` 互斥。如果你以其中一种格式获取响应正文，就无法再从 `response` 对象。
{% endhint %}

{% hint style="warning" %}
**📔 注意**：每个 Decentraland 场景一次只允许执行一个 `fetch` 命令。这不会影响场景代码必须如何组织，因为请求会在内部排队。如果你的场景需要向不同端点发送多个请求，请记住，每个请求只有在前一个请求收到响应后才会发送。
{% endhint %}

## 签名请求

你可以采用一种额外的安全措施，以确认请求是否源自 Decentraland 内的玩家会话。你可以在请求中附加签名；该签名使用 Decentraland 会话为每位玩家基于玩家地址生成的临时密钥进行签名。接收该请求的服务器随后可以验证该签名消息确实与当前在世界中处于活动状态的地址相匹配。

当玩家有动机利用系统刷取代币或游戏积分时，这类安全措施尤其有价值。

要发送签名请求，你只需使用 `signedFetch()` 函数，其用法与 `fetch()` 函数。

```ts
import { signedFetch } from '~system/SignedFetch'

executeTask(async () => {
	try {
		let response = await signedFetch({
			url: callUrl,
			init: {
				headers: { 'Content-Type': 'application/json' },
				method: 'POST',
				body: JSON.stringify(myBody),
			},
		})

		if (!response.ok) {
			throw new Error('无效的响应')
		}

		let json = JSON.parse(response.body)

		console.log('已收到响应：', json)
	} catch {
		console.log('无法访问 URL')
	}
})
```

该请求还包含一组额外的标头，其中包括签名消息和一组用于解释它的元数据。签名消息由请求的全部内容组成，这些内容使用玩家的临时密钥进行加密。

该 `signedFetch()` 不同于 `fetch()` 函数之处在于，其响应是完整 HTTP 消息的一个 Promise，表示为一个 `FlatFetchResponse` 对象。它包括以下属性：

* `body`
* `headers`
* `ok`
* `status`
* `statusText`

该 **body** 始终是一个字符串，你可以像上面的示例那样解析它。

### 验证签名请求

要使用签名请求，接收这些请求的服务器应验证签名是否与请求的其余部分匹配，并且签名消息中编码的时间戳是否为当前时间。

你可以在以下示例场景中找到执行此任务的服务器的简单示例：

[验证玩家真实性](https://github.com/decentraland-scenes/validate-player-authenticity)

## 请求超时

如果 HTTP 请求等待响应的时间过长，就会失败，以便可以发送其他请求。对于 `fetch()`，默认超时时间阈值为 30 秒，但你可以通过配置 `timeout` 该属性。其值 `timeout` 以毫秒表示。

```ts
fetch('https://some-url.com', { timeout: 1000 })
```

## 使用 WebSockets

你也可以向 WebSocket 服务器发送和获取数据，只要该服务器使用安全连接，并采用 *wss*.

```ts
var socket = new WebSocket('url')

socket.onmessage = function (event) {
	console.log('收到 WebSocket 消息：', event)
}
```

使用 WebSockets 的语法与 JavaScript 原生实现的语法没有区别。请参阅 [Mozilla Web API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) 中的文档，了解如何通过 WebSockets 接收和发送消息的详细信息。

{% hint style="info" %}
**💡 提示**：有一个简化 websocket 连接使用的库，并且已被证明与 Decentraland 配合得非常好，它是 [Colyseus](https://colyseus.io/)。其他一些 websocket 库与 Decentraland SDK 不兼容。

它在 websocket 连接之上构建了一层抽象，使得对变化作出反应以及在服务器中远程存储一致的游戏状态变得极其简单。你可以在以下示例中看到它的实际应用：

* [Cube Jumper](https://github.com/decentraland-scenes/cube-jumper-colyesus-sdk7)
* [Space Traitor](https://github.com/decentraland-scenes/Space-Traitor)
* [AI NPC](https://github.com/decentraland-scenes/inworld-ai-sdk7)
  {% endhint %}

## 调试网络请求

你可以通过打开 Debug Panel 来调试网络请求。

要打开 Debug Panel，你可以点击 ![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-92fe4dd70621a496d0da083ae9b5f9b2ef84d2dd%2Fdebug-icon.png?alt=media\&token=42a33cd5-b516-43ea-a6b3-8c33c21e4359) 右上角的图标。然后选择 **网络请求** 选项卡并点击 **打开 Chrome Devtools**.

这将打开一个新的 Chrome 窗口，并显示已打开的 Network 选项卡。

参见 [在预览中调试](/creator/content-creator-zh/chang-jing-sdk7/tiao-shi/debug-in-preview.md#web-requests) 了解更多详情。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/lian-wang/network-connections.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
