📜  Godot 跨站 (1)

📅  最后修改于: 2023-12-03 15:31:00.769000             🧑  作者: Mango

Godot 跨站

Godot 是一款免费开源的游戏引擎,可以用于制作二维和三维游戏。在 Web 开发中,我们常常需要向不同的域名发送 HTTP 请求,这就涉及到了跨站问题。

什么是跨站?

简单来说,跨站指的是浏览器从一个网站获取资源时,向另一个域名下的资源发起的请求。因为浏览器对于不同域名下的资源有跨域限制,所以跨站请求可能会被浏览器阻止。

如何解决跨站问题?

在 Web 开发中,有以下几种解决跨站问题的方式:

JSONP

JSONP 是一种利用 <script> 标签进行跨域请求的技术。具体操作是在前端页面中动态创建一个 <script> 标签,其 src 属性指向后端提供的 JSONP 接口地址,该接口返回格式为 callback({"data": "value"}) 的 JavaScript 代码。前端通过指定一个回调函数来处理返回的 JSON 数据。

JSONP 的缺点是请求只能为 GET 请求,且后端最终返回的代码需要前端开发者自行处理,存在一定的风险性。

CORS

CORS(跨域资源共享)是一种在服务端设置的方式,通过在 HTTP 请求头加上 Access-Control-Allow-Origin 来告诉浏览器哪些域名可以访问该资源,从而允许跨域请求。

CORS 的优点是可以使用任意 HTTP 请求方式,且所有代码都由后端开发者处理,更加安全可靠。

postMessage

postMessage 是一种在不同窗口和域之间通信的方式。具体操作是在前端页面中使用 JavaScript 发送消息(Message)给 iframe 或者其他窗口,通过指定源(origin)来确保消息只被发送到特定的接收窗口。

postMessage 的优点是可以进行更加复杂的跨域通信,支持多种数据类型和格式。

Godot 中的跨站问题

在 Godot 中,可以通过内置的 HTTPClient 类来发送 HTTP 请求。由于浏览器的跨域限制,当我们向不同的域名发送 HTTP 请求时,可能会出现请求失败或者跨站问题。

Godot 中解决跨站问题也有多种方式:

使用 JSONP
  1. 在前端页面中动态创建 <script> 标签,设置其 src 属性为后端提供的 JSONP 接口地址,并指定回调函数。

  2. 在 HTTPClient 类的 request 方法中进行 GET 请求。

以下是 Python 代码:

func send_jsonp_request(url: String):
    var client = HTTPClient.new()
    var request_url = url
    var callback_func = "my_callback_func" # 回调函数名称
    request_url += "?callback=" + callback_func

    client.connect("request_completed", self, "_on_request_completed")
    client.request(HTTPClient.METHOD_GET, request_url)

func _on_request_completed(result, response, headers, body):
    if result == HTTPClient.RESULT_SUCCESS:
        # 处理返回的 JSON 数据
        # ...

在前端页面中,需要定义回调函数 my_callback_func 来处理 JSONP 接口返回的数据:

function my_callback_func(data) {
    // 处理返回的数据
    // ...
}
使用 CORS

使用 CORS 的方式需要后端设置响应头,告诉浏览器允许哪些域名跨域访问该资源。具体方法可以参考后端语言的文档。

在 Godot 中,设置请求头可以通过 HTTPClient 实例的 set_request_header 方法来实现:

func send_cors_request(url: String):
    var client = HTTPClient.new()
    var request_url = url

    client.connect("request_completed", self, "_on_request_completed")
    client.set_request_header("Origin", "https://example.com") # 设置请求头
    client.request(HTTPClient.METHOD_GET, request_url)

func _on_request_completed(result, response, headers, body):
    if result == HTTPClient.RESULT_SUCCESS:
        # 处理返回的 JSON 数据
        # ...
使用 postMessage

使用 postMessage 的方式需要在 Godot 中创建 iframe,并将其指向后端提供的跨域页面。然后使用 JavaScript 发送消息给该 iframe,从而实现跨域通信。

以下是 Python 代码:

func send_postmessage_request(url: String):
    var iframe_name = "my_iframe" # iframe 的名称
    var iframe_url = url
    var target_origin = "https://example.com" # 接收窗口的地址

    # 创建 iframe
    var iframe = OS.get_singleton().create_window()

    # 设置 iframe 的属性
    iframe.set_name(iframe_name)
    iframe.set_title(iframe_name)
    iframe.set_position(Vector2(0, 0))
    iframe.set_rect(
        Rect2(0, 0, get_viewport_rect().size.x, get_viewport_rect().size.y)
    )
    iframe.set_always_on_top(true)
    iframe.show()
    iframe.set_as_transparent_background(true)

    # 加载 iframe
    iframe.set_load_when_visible(true)
    iframe.set_parent(self)
    iframe.load(url)

    # 在 iframe 加载完成后,发送 postMessage 消息
    func _on_frame_load_finished():
        iframe.rpc("post_message_to_iframe", target_origin)

    iframe.connect("visibility_changed", self, "_on_frame_visibility_changed")
    iframe.connect("load_finished", self, "_on_frame_load_finished")

# 在 iframe 加载完成后,调用该方法
func post_message_to_iframe(target_origin: String):
    # 发送 postMessage 消息
    JS.eval("window.parent.postMessage('message', target_origin)")

在后端页面中,需要使用 JavaScript 监听 postMessage 事件,从而获取前端发送的数据:

window.addEventListener('message', function(event) {
    // 处理接收到的数据
    // ...
}, false);
总结

以上是 Godot 中解决跨站问题的三种方式。每种方式都有其适用的场景和应用范围,具体选择哪种方式需要根据实际情况进行判断。