首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >腾讯云SCF + 腾讯云API网关实现跨域

腾讯云SCF + 腾讯云API网关实现跨域

原创
作者头像
孔令飞
修改于 2019-11-01 04:28:58
修改于 2019-11-01 04:28:58
18K00
代码可运行
举报
文章被收录于专栏:ServerlessServerless
运行总次数:0
代码可运行

跨域介绍

跨来源资源共享(Cross-Origin Resource Sharing(CORS))是一种使用额外 HTTP 标头来让目前浏览网站的 user agent 能获得访问不同来源(网域)服务器特定资源之权限的机制。当 user agent 请求一个不是目前文件来源——来自于不同网域(domain)、通信协定(protocol)或通信端口(port)的资源时,会建立一个跨来源HTTP请求(cross-origin HTTP request)。

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域:

当前页面 url

被请求页面 url

是否跨域

原因

http://www.example.com/

http://www.example.com/index.html

同源(协议、域名、端口号相同)

http://www.example.com/

https://www.example.com/index.html

跨域

协议不同(http/https)

http://www.example.com/

http://www.baidu.com/

跨域

主域名不同(example/baidu)

http://www.example.com/

http://blog.example.com/

跨域

子域名不同(www/blog)

http://www.example.com:8080/

http://www.example.com:7001/

跨域

端口号不同(8080/7001)

跨域种类

一共有 2 种跨域请求:

  1. 简单请求
  2. 预检请求

简单请求

当 HTTP 请求出现以下两种情况时,浏览器认为是简单跨域请求:

  1. 请求方法是 GET、HEAD 或者 POST,并且当请求方法是 POST 时,Content-Type 必须是 application/x-www-form-urlencoded, multipart/form-data 或着 text/plain 中的一个值。
  2. 请求中没有自定义 HTTP 头部。

对于简单跨域请求,浏览器要做的就是在 HTTP 请求中添加 Origin Header,将 JavaScript 脚本所在域填充进去,向其他域的服务器请求资源。服务器端收到一个简单跨域请求后,根据资源权限配置,在响应头中添加 Access-Control-Allow-Origin Header。浏览器收到响应后,查看 Access-Control-Allow-Origin Header,如果当前域已经得到授权,则将结果返回给 JavaScript。否则浏览器忽略此次响应。相较于同源请求,CORS 简单请求会在头信息中额外增加一个 Origin 字段。

预检请求

当 HTTP 请求出现以下两种情况时,浏览器认为是带预检(Preflighted)的跨域请求:

  1. 除 GET、HEAD 和 POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他 HTTP 方法。
  2. 请求中出现自定义 HTTP 头部。

非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为"预检"请求(preflight)。

预检(preflighted)请求会先用 HTTP 的 OPTIONS 方法请求另一个域名资源,确认后续实际(actual)请求能否可安全送出。由于跨域请求可能会携带使用者的信息,所以要先进行预检请求。

腾讯云SCF + 腾讯云API 网关实现跨域

当 SCF 绑定 API 网关触发器后,有 2 种方式实现跨域**(建议使用第 1 种方法)**:

  1. 借助 API 网关的跨域功能
  2. 云函数中实现跨域逻辑

本文就来介绍下,如果通过这 2 种方式,来实现跨域功能。建议选择第 1 种方式,来实现跨域功能,这样用户就不需要在函数中实现跨域相关的逻辑代码。

借助 API 网关的跨域功能

Step1. 绑定 API 网关触发器

绑定 API 网关触发器:

  1. 请求方法:GET/POST/HEAD/PUT/DELETE(根据需要进行选择)

目前 API 网关当请求方法为 ANY 时,无法开启跨域功能,所以这里请求方法不能选择 ANY

Step2. 在 API 网关产品页面,开启 API 的跨域功能

1、在 API网关 产品页面,选择绑定的 API 服务和绑定的 API,编辑 API:

2、在编辑页面开启:支持CORS 选项

3、保存设置后,发布 API

Step3. 测试跨域功能

1、简单跨域请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ curl -v -X GET -H "Origin: http://example.com"  http://service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com/test/corstest
* About to connect() to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com port 80 (#0)
*   Trying 111.231.97.251...
* Connected to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com (111.231.97.251) port 80 (#0)
> GET /test/corstest HTTP/1.1
> User-Agent: curl/7.29.0
> Host: service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com
> Accept: */*
> Origin: http://example.com
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Api-ID: api-bzh0ss12
< X-Service-RateLimit: 5000/5000
< X-Api-RateLimit: unlimited
< Date: Thu, 31 Oct 2019 23:25:46 GMT
< Access-Control-Allow-Origin: http://example.com
< Access-Control-Allow-Credentials: true
< Access-Control-Expose-Headers: X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type
<
* Connection #0 to host service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com left intact
cors template function run successfully

2、预检跨域请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ curl -v -X OPTIONS -H "Access-Control-Request-Method: GET" http://service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com/test/corstest
* About to connect() to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com port 80 (#0)
*   Trying 111.231.97.251...
* Connected to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com (111.231.97.251) port 80 (#0)
> OPTIONS /test/corstest HTTP/1.1
> User-Agent: curl/7.29.0
> Host: service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com
> Accept: */*
> Access-Control-Request-Method: GET
>
< HTTP/1.1 204 No Content
< Date: Thu, 31 Oct 2019 23:24:53 GMT
< Connection: keep-alive
< X-Api-ID: api-bzh0ss12
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type
< Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
< Access-Control-Max-Age: 86400
< Server: apigw/1.0.15
<
* Connection #0 to host service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com left intact

可以看到,网关均正确返回跨域需要的 Headers。

开启跨域后,OPTIONS 请求不走鉴权逻辑

云函数中实现跨域逻辑

Step1. 创建带跨域逻辑的云函数

创建函数:

  1. 运行环境: Python2.7
  2. 选择 空白模板
  3. 执行方法: index.main_handle

函数代码为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-

import logging

logger = logging.getLogger()

response = {"isBase64": False, "statusCode": 200, "headers": {}}

def set_simple_cors():
    response["headers"]["Access-Control-Allow-Origin"] = "*"
    response["headers"]["Access-Control-Allow-Credentials"] = "true"
    response["headers"]["Access-Control-Expose-Headers"] = "X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type"
    return response

def set_preflight_cors():
    response["headers"]["Access-Control-Allow-Origin"] = "*"
    response["headers"]["Access-Control-Allow-Credentials"] = "true"
    response["headers"]["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH"
    response["headers"]["Access-Control-Allow-Headers"] = "X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type"
    response["headers"]["Access-Control-Max-Age"] = 86400
    return response

def is_simple_cors(httpMethod, headers):
    simple_methods = ['HEAD', 'GET', 'POST']
    simple_headers = ['accept', 'accept-language', 'content-language', 'last-event-id', 'content-type', 'origin']
    allow_content_types = ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain']

    if httpMethod not in simple_methods:
        return False

    if httpMethod == "POST" and headers['content-type'] not in allow_content_types:
        return False

    for header in headers:
        if header not in simple_headers:
            return False

    return True

def is_preflight_cors(httpMethod, headers):
    httpPreflightMethod = headers.get('access-control-request-method', '')
    if httpMethod == "OPTIONS" and httpPreflightMethod != "":
        return True

    return False

def main_handler(event, context):
    logger.info('start cors template function')
    logger.info("event: %s", event)

    httpMethod = event['httpMethod']
    headers = event['headers']

    # 跨域:预检请求
    if is_preflight_cors(httpMethod, headers):
        logger.info("receive preflight http cors request")
        return set_preflight_cors()

    # 跨域:简单请求
    if is_simple_cors(httpMethod, headers):
        logger.info("receive simple http cors request")
        set_simple_cors()

    # 同源请求,正常完成业务逻辑
    logger.info("receive normal http request.")
    body = "cors template function run successfully"
    response["body"] = body
    return response

Step2. 绑定 API 网关触发器

绑定 API 网关触发器:

  1. 请求方法: ANY
  2. 开启 启用集成响应

开启集成响应后,返回的参数需要满足集成响应的格式。

参考文档:集成响应与透传响应 - https://cloud.tencent.com/document/product/583/12513#.E9.9B.86.E6.88.90.E5.93.8D.E5.BA.94.E4.B8.8E.E9.80.8F.E4.BC.A0.E5.93.8D.E5.BA.94

Step3. 测试跨域功能

1、简单跨域请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ curl -v -X GET -H "Origin: http://example.com" http://service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com/test/corstest
* About to connect() to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com port 80 (#0)
*   Trying 111.231.97.251...
* Connected to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com (111.231.97.251) port 80 (#0)
> GET /test/corstest HTTP/1.1
> User-Agent: curl/7.29.0
> Host: service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com
> Accept: */*
> Origin: http://example.com
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Api-ID: api-51u298ne
< X-Service-RateLimit: 5000/5000
< X-Api-RateLimit: unlimited
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type
< Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
< Access-Control-Allow-Origin: *
< Date: Fri, 01 Nov 2019 00:08:50 GMT
<
* Connection #0 to host service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com left intact
cors template function run successfully

2、 预检跨域请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ curl -v -X OPTIONS -H "Access-Control-Request-Method: GET" http://service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com/test/corstest
* About to connect() to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com port 80 (#0)
*   Trying 111.231.97.251...
* Connected to service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com (111.231.97.251) port 80 (#0)
> OPTIONS /test/corstest HTTP/1.1
> User-Agent: curl/7.29.0
> Host: service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com
> Accept: */*
> Access-Control-Request-Method: GET
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< X-Api-ID: api-51u298ne
< X-Service-RateLimit: 5000/5000
< X-Api-RateLimit: unlimited
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: X-Api-ID,X-Service-RateLimit,X-UsagePlan-RateLimit,X-UsagePlan-Quota,Cache-Control,Connection,Content-Disposition,Date,Keep-Alive,Pragma,Via,Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cookie,Expect,From,Host,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Range,Origin,Referer,User-Agent,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,Accept-Range,Age,Content-Range,Content-Security-Policy,ETag,Expires,Last-Modified,Location,Server,Set-Cookie,Trailer,Transfer-Encoding,Vary,Allow,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-Type
< Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS,PATCH
< Access-Control-Allow-Origin: *
< Date: Fri, 01 Nov 2019 00:07:40 GMT
<
* Connection #0 to host service-4mlv1c3l-1253970226.ap-shanghai.apigateway.myqcloud.com left intact

可以看到,函数均正确返回跨域需要的 Headers。

API 网关后期产品优化

目前 ANY 方法还不支持跨域设置,这个 API 网关后期会考虑支持。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
无服务器云函数python实时新闻爬虫(自带api网关)
https://github.com/birdsofsummer/news_spider
用户1348396
2019/08/13
3.7K0
无服务器云函数python实时新闻爬虫(自带api网关)
CDN-COS常见跨域问题汇总
前端开发在使用CDN-COS产品时,经常会遇到应用上的跨域访问,腾讯云COS和CDN两款产品都可以自主设置跨域响应头,但又有一些差异,本文介绍一下常见的访问失败的问题和验证方式。
wainsun
2021/02/23
3.1K0
CDN-COS常见跨域问题汇总
对象存储 COS 帮您轻松搞定跨域访问需求
早期为了避免 CSRF(跨站请求伪造) 攻击,浏览器引入了 “同源策略” 机制。如果两个 URL 的协议,主机名(域名/IP),端口号一致,则视为这两个 URL “同源”,属于同一个 “域”,否则视为 “非同源”,即 “跨域”。浏览器会主动拦截跨域的 AJAX 请求,以规避安全风险。
云存储
2021/01/27
2.3K0
对象存储 COS 帮您轻松搞定跨域访问需求
CDN-COS常见跨域问题汇总
前端开发在使用CDN-COS产品时,经常会遇到应用上的跨域访问,腾讯云COS和CDN两款产品都可以自主设置跨域响应头,但又有一些差异,本文介绍一下常见的访问失败的问题和验证方式。
wainsun
2020/09/14
4.8K0
前后端分离项目,如何解决跨域问题
CORS全称Cross-Origin Resource Sharing,意为跨域资源共享。当一个资源去访问另一个不同域名或者同域名不同端口的资源时,就会发出跨域请求。如果此时另一个资源不允许其进行跨域资源访问,那么访问的那个资源就会遇到跨域问题。
macrozheng
2019/08/01
2.4K0
前后端分离项目,如何解决跨域问题
CORS跨域
当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
张炳
2019/08/02
2.2K0
CORS跨域
gin 跨域问题
跨域请求时需要考虑到options请求,这种请求需要直接返回200。在跨域前,会首先发出options请求,然后通过后,浏览器才会真正的发送跨域的请求。
Java架构师必看
2021/05/14
1K0
Nginx跨域了解及模拟和解决
何为同源: 1.协议(http/https)相同 2.域名(IP)相同 3.端口相同
iginkgo18
2021/07/07
1.3K1
跨域资源共享(CORS)
简单先了解一下CORS,方便我们后续去挖一些CORS的漏洞,最近CORS也是比较火的!
黑伞安全
2019/10/16
4K0
怎么解决跨域
存在浏览器同源策略,所以才会有跨域问题。那么浏览器是出于何种原因会有跨域的限制呢。其实不难想到,跨域限制主要的目的就是为了用户的上网安全。
程序员子龙
2024/04/30
2670
Nginx 设置cors跨域
提示:有时候我们的后端是PHP文件,则需要把跨域的代码加 location ~ \.php(.*)$ 中。
ITer.996
2019/08/28
2.5K0
GIN框架解决跨域问题
当两个域具有相同的协议(如http), 相同的端口(如80),相同的host,那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。
Porco1Rosso
2020/05/28
4.1K0
GIN框架解决跨域问题
跨域共享CORS详解及Gin配置跨域
跨域简介 当两个域具有相同的协议(如http), 相同的端口(如80),相同的host,那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。 跨域就指着协议,域名,端口不一致,出于安全考虑,跨域的资源之间是无法交互的(例如一般情况跨域的JavaScript无法交互,当然有很多解决跨域的方案) 解决跨域几种方案 /* CORS 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可, 前端无须设置,若要带cookie请求:前后端都需要设置。
iginkgo18
2020/12/01
1.9K0
知识分享之Golang——Gin学习之开放所有接口的OPTION方法
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。
cn華少
2021/12/10
1.8K0
后端工程师需要了解的跨域知识
产品有多端:机构端,局方端 ,家长端等 。每端都有独立的域名,有的是在PC上访问,有的是通过微信公众号来访问,有的是扫码后H5展现。
勇哥java实战
2022/01/14
1.1K0
后端工程师需要了解的跨域知识
跨域问题的一次深入研究
最近在业务代码中深受跨域问题困扰,因此特别写一篇博客来记录一下自己对跨域的理解以及使用到的参考资料。本文的项目背景基于vue+vuex+axios+springboot。涉及以下内容:
眯眯眼的猫头鹰
2018/10/31
1.6K0
014.Nginx跨域配置
同源策略是一个安全策略。同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。
木二
2020/07/21
7.6K0
014.Nginx跨域配置
跨域问题及解决方案
在前后端分离项目中,跨域问题是一定会遇到的。跨域问题的出现,会导致css、js或者ajax对后端请求等资源无法访问的情况。
半月无霜
2023/03/03
1.2K0
跨域问题及CORS解决跨域问题方法
跨域不一定会有跨域问题。因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。
Java架构师必看
2021/03/22
13.1K0
跨域的解决方式(java后端)
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么Ajax就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。
Java微观世界
2025/01/21
4280
跨域的解决方式(java后端)
相关推荐
无服务器云函数python实时新闻爬虫(自带api网关)
更多 >
LV.1
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验