【Koa】KOA 基础-掌握基于koa2搭建web应用的基础

目录

  • KOA 基础
  • 框架介绍与环境搭建
    • koa2 基本介绍
    • Node.JS 环境安装
    • 创建 Hello World 程序
  • Web 应用开发基础
    • 处理get请求参数
    • 处理post请求参数
    • 响应一个页面
    • 处理静态资源
  • 中间件
    • 基本概念和执行过程
      • 中间件概念理解
      • Koa 中间件执行模型-洋葱圈模型
      • Koa洋葱圈设计理解
    • 用 koa-body 处理 POST 传参
    • 用 koa-views 和 EJS 渲染页面
    • 用 koa-static 处理静态资源
    • 用 koa-body 处理文件上传
    • 用 koa-router 实现后端路由

KOA 基础

课程目标:掌握基于koa2搭建web应用的基础


框架介绍与环境搭建

koa2 基本介绍

本章目标: 认识 KOA

Koa 和 Express 一样,都是基于 node.js 的 Web 应用开发框架。

Koa 2 是 Koa 的 2.0 版本。

image-20210526115054161

koa:下一代的 node.js Web 框架!

  • 由 Express 框架原班人马设计和开发
  • 比 Express 更有表现力、更健壮(异步处理支持 async / await,所以可以用 try / catch 来更好的处理异常)
  • 框架核心默认不带有任何中间件,更精简、更快速(而 Express 默认自带了很多的中间件)
  • 更强大的中间件模型(洋葱圈模型)

典型应用场景:

  • 开发 REST API
  • 开发 WebSocket API
  • 开发服务端渲染的页面

本章问题:

  1. koa 框架可以用来做什么?
  2. koa 框架默认自带中间件吗?

Node.JS 环境安装

本章目标: 完成NodeJS环境安装

开发和运行 koa 必须依赖 node.js,因此需要先安装它

koa 2 支持 async 函数,但是 node.js 7.6 以后才原生支持 async, NodeJS 7.6+

目前 node.js 稳定版已经是 14+ 了,因此大家安装最新的稳定版即可。

node.js 稳定版下载地址

安装步骤

一路下一步即可。推荐不要安装在包含中文的路径下。

安装验证

打开命令行,执行以下命令

node -v

# 如能看到输出一个版本号,如 v14.17.0 即代表安装成功

创建 Hello World 程序

本章目标: 使用 koa 框架编写一个最简单的 API,访问时页面响应 hello world

步骤:

  1. 创建新的工程目录,比如:hello 目录

  2. 安装依赖包

npm i koa
  1. 创建代码文件,比如:app.js 文件
// 1. 引入 koa
const Koa = require('koa')

// 2. 创建 koa 实例
const app = new Koa()

// 3. 创建一个中间件,所有的请求都会执行到这个中间件进行处理
//   Koa 提供一个 Context 对象,表示一次对话的上下文(包括 HTTP 请求和 HTTP 回复)。
//   通过加工这个对象,就可以控制返回给用户的内容。
app.use(async ctx => {
  // 为方便起见许多上下文的访问器和方法直接委托给它们的 ctx.request 或 ctx.response
  // 例如: ctx.body => ctx.response.body
    
  // 设置响应体  ctx.body = 'xxx'
  ctx.response.body = 'Hello,World'
})

// 4. 启动 koa 实例所关联的 http 服务器,并监听在 3000 端口上向外提供服务
app.listen(3000, () => {
  // http 服务器启动成功后执行本回调函数
  console.log('请访问 http://localhost:3000')
})

  1. 在命令行执行
node server.js
  1. 在浏览器访问 http://localhost:3000

Web 应用开发基础

处理get请求参数

**本章目标: 学习 koa中 如何处理 get 请求参数 **

在中间件中获取 GET 请求发送的查询字符串参数

中间件函数的第一个参数 ctx 中包含了请求和响应相关的操作,我们可以通过它的 query 属性来获取请求的查询字符串参数:

app.use(async ctx => {
  // 方式一:获取对象形式的查询字符串参数
  console.log("查询字符串参数(对象形式)", ctx.request.query)   				
  
  // 方式二:获取原始字符串形式的查询字符串参数
  console.log("查询字符串参数(字符串形式)", ctx.request.querystring)   
  
  // ...
})

处理post请求参数

本节目标: 学会处理 POST 请求参数

在中间件中获取 POST 请求通过请求体发送的参数数据

获取 POST 请求发送的请求体参数,相对较为繁琐,大致思路为:

  1. 监听 node.js 原生请求对象的 data 事件,从请求体中获取数据,并将所有数据拼合起来(因为如果请求体中携带的数据量较大,就会分几次来触发 data 事件,逐步获取)
  2. 监听 node.js 原生请求对象的 end事件,获知请求体数据被完全获取

代码示例:

// ...

app.use(async ctx => {
  let paramStr = ''

  // 1. 监听 node.js 原生 Request 对象的 data 事件,获取请求体数据
  ctx.req.on('data', (data) => {
    // 从请求体中获取数据,并拼接成一整个字符串
    paramStr += data
  })

  // 2. 监听 node.js 原生 Request 对象的 end 事件,结束请求体数据获取
  ctx.req.on('end', () => {
    // paramStr 是查询字符串格式的数据 可以用 new URLSearchParams 解析
    // 语法: var URLSearchParams = new URLSearchParams(init);
    const params = new URLSearchParams(paramStr)
    
    console.log('请求体参数(字符串形式)', paramStr);
    console.log('请求体参数(对象形式)', params);
  })

	// ...
})

URLSearchParams 语法说明:

const params = new URLSearchParams('k=%E5%85%B3%E9%94%AE%E5%AD%97&p=1');
console.log(params.get('k'));   // 返回字符串“关键字”,支持自动 UTF-8 解码
console.log(params.get('p'));   // 返回字符串“1”
console.log(params.get('xxx')); // 如果没有 xxx 这个键,则返回 null
console.log(params.has('xxx')); // 当然也可以通过 has() 方法查询是否存在指定的键
console.log(params.keys());     // 返回一个 ES6 Iterator,内含 ['k', 'p']
console.log(params.values());   // 返一个 ES6 Iterator,内含 ['关键字', '1']

MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams/URLSearchParams

知乎: https://zhuanlan.zhihu.com/p/29581070


响应一个页面

本节目标: 收到请求后,给客户端响应一个 HTML 内容

方式一:直接响应一个 HTML 字符串给客户端

app.use(async ctx => {
  // 为响应体设置 HTML 字符串内容
  ctx.body = `
    <!DOCTYPE html>
    <html lang="en">

    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<title>Document</title>
    </head>

    <body>
    	<h1>你好,世界</h1>
    </body>

    </html>
	`
})

方式二:读取 html 文件后,将读取到的 HTML 字符串响应给客户端

<!-- 编写 index.html 文件 -->

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>

  <body>
    <h1>你好,世界</h1>
  </body>

</html>
// 导入文件读取模块
const fs = require('fs')

// 读取 html 文件的工具函数
function getHtmlFile(filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, (err, data) => {
      if (err) {
        reject(err)
      } else {
	    // 读取的文件数据是 Buffer 形式,要用 toString() 转成字符串
        resolve(data.toString())
      }
    })
  })
}

app.use(async ctx => {
  // 读取 index.html 文件后,设置到响应体
  ctx.body = await getHtmlFile('./index.html')
})

处理静态资源

本节目标: 收到请求后,给客户端响应静态资源内容,比如图片

处理静态资源的思路,和之前响应 html 文件给客户端是类似的,也是先读取文件,再设置给响应体。

以下是响应一张图片的实例:

  1. 先在项目目录中建立一个 static 目录,并放置一张图片文件(本例中是 01.jpg)
  2. 编写下面的代码,实现读取图片并响应给客户端的操作
// 导入文件读取模块
const fs = require('fs')

// 获取静态资源文件的
function getImageFile(filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, (err, data) => {
      if (err) {
        reject(err)
      } else {
        // 这里保持 Buffer 格式数据,因为图片是二进制数据,不要转成字符串
        resolve(data)
      }
    })
  })
}

app.use(async ctx => {
  // 【重要】正确设置静态资源的 Content-Type 响应头,否则在浏览器中只会下载文件,不能查看到图片
  ctx.set('Content-Type', 'image/jpeg')

  // 在响应体中设置读取到的图片文件数据
  ctx.body = await getImageFile('./static/01.jpg')
})

中间件

基本概念和执行过程

本节目标: 了解什么是中间件,以及它的作用

基本概念

中间件,其实就是一系列用来 对请求进行处理函数

中间件概念理解

为了理解中间件,我们先来看一下我们现实生活中的例子
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

处理污水的这三个中间处理环节,就可以叫做中间件。

Koa 中间件执行模型-洋葱圈模型

本节目标: 理解Koa中间件执行模型 - 洋葱圈模型

在 Koa 中可以为 Koa 实例添加多个中间件,让一个请求可以经过多个中间件函数的处理。

中间件函数的格式为:

function someMiddleware(ctx, next) {
  // ... 对请求进行处理的逻辑 ...
  
}

每个中间件函数都有两个参数:

  • ctx - 请求上下文对象,它包含和请求和响应相关的数据和操作
  • next - 是一个函数,调用后会执行下一个中间件

创建好中间件函数后,可以将它添加到 Koa 实例上:

app.use(someMiddleware)

Koa 中间件的执行模型

6383319-09c1061cf194e0b8

上面为 Koa 框架的中间件模型示意图,看上去像个洋葱,所以我们称它为《洋葱圈模型》。

它的含义就是说:

Koa 中间件的执行就像洋葱一样,最早被 use 的中间件会放在最外层,而后续被 use 的中间件会往里层放;

当接收到一个请求的时候,处理顺序是:

1. 从左到右从洋葱的最外层到最里层,也就是从最早 use 的中间件到最后 use 的中间件依次执行;
2. 在到达最里层中间件后,会继续向右逐层往外执行,直到最外层中间件,然后返回 response

示例代码:

app.use(async (ctx, next) => {
    console.log('>>>>>>>> A 111')
    await next()
    console.log('>>>>>>>> A 222')
})

app.use(async (ctx, next) => {
    console.log('>>>>>>>> B 111')
    await next()
    console.log('>>>>>>>> B 222')
})

当接收请求后,我们可以看到控制台打印如下结果:

>>>>>>>> A 111
>>>>>>>> B 111
>>>>>>>> B 222
>>>>>>>> A 222

由此可知,一般情况下 Koa 的中间件都会执行两次:

  • 调用 next 之前为第一次。在调用 next 后,会把控制权传递给往里层的下一个中间件
  • 当里层不再有任何中间件、或未调用 next 函数时,就开始依次往外层中间件执行,执行的是外层中间件中调用 next 函数之后的代码

本章问题

  1. 中间件函数, 有哪两个形参?
  2. Koa 中中间件执行的模型叫什么?

Koa洋葱圈设计理解

6383319-09c1061cf194e0b8

两个现象:

  • 中间件的执行了两次
  • 执行顺序奇怪,以next函数为分界点:先use的中间件,next前的逻辑先执行,但next后的逻辑反而后执行

思考: 为什么 Koa 要这么设计? 正常不应该是中间件按顺序从开始到结束执行吗?

说明:

  • 如果说使用中间件的场景, 不存在前后依赖的情况,从头到尾按顺序链式调用 => 完全没问题。

  • 但是, 如何存在依赖的情况呢? 比如: 前一个中间件部分代码, 依赖于下一个中间件的处理结果?

    链式一次执行就无法实现了!

结论:

  • next 前的逻辑 : 进行前期处理
  • 调用next,将控制流交给下个中间件,并await其完成,直到后面没有中间件或者没有next函数执行为止
  • 完成后一层层回溯执行各个中间件的后期处理(next 后的逻辑)

用 koa-body 处理 POST 传参

本节目标: 使用 koa-body 中间件 处理 POST 传参

我们自己来处理获取 POST 请求的参数比较繁琐,实际开发中可以使用封装好的开源中间件

我们可以在 Koa 官方wiki 上找到很多优秀的开源中间件。而 koa-body 是一个专门用于获取通过请求体传递的数据的中间件。

使用步骤:

  1. 安装依赖包
npm i koa-body
  1. 引入并使用 koa-body
// 引入 koa-body
const koaBody = require('koa-body')

// ...

// 为 Koa 实例设置 koa-body 中间件
app.use(koaBody())

app.use(async ctx => {
  // 通过 ctx.request.body 获取请求体参数
  console.log('请求体参数', ctx.request.body)
  ctx.body = 'Hello'
})

用 koa-views 和 EJS 渲染页面

本节目标: 在 Koa 中使用模板引擎 EJS 来进行页面的动态渲染

在 Koa 中,我们也可以使用模板引擎,通过模板语法将数据动态渲染成html页面内容,然后发送到客户端去。

koa-views 是一个支持使用多种模板引擎来渲染页面的中间件,在本章中我们要使用 EJS 模板。

使用步骤:

  1. 安装 koa-views 中间件 和 ejs 模板引擎
npm i koa-views ejs
  1. 引入并使用中间件
// 引入 koa-views
var views = require('koa-views');

// 配置和应用 koa-views 中间件(这里配置使用了 ejs 模板引擎,以及模板文件的存放目录)
app.use(views(__dirname + '/views', { extension: 'ejs' }))

// 引入 koa-views 后,就可以使用 ctx.render 函数渲染 ejs 模板文件了
app.use(async ctx => {
  // render 函数的第一个参数是模板文件名;第二个参数是要渲染到模板中的动态数据
  await ctx.render('test', {
    name: '小明',
    age: 18,
    books: ['三国演义', '红楼梦', '西游记', '水浒传']
  })
})

模板文件 views/test.ejs

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div>姓名:<%= name %></div>
    <div>年龄:<%= age %></div>
    <ul>
        <% books.forEach(function (book) { %>
            <li><%= book %></li>
        <% }) %>
    </ul>
</body>

</html>

用 koa-static 处理静态资源

本节目标: koa-static中间件, 处理静态资源

我们自己处理静态资源的话,代码会较为繁琐,因此实际开发中可以借助封装好开源中间件,比如 koa-static

查看 koa-static 中间件

使用步骤:

  1. 安装依赖包
npm i koa-static
  1. 创建 static 目录,并放入一些静态资源文件(图片等)

  2. 配置中间件

// 引入 koa-body
const koaStatic = require('koa-static')

// ...

// 调用 koaStatic() 能自定义一些配置,并返回一个真正的 koa-static 中间件函数,然后设置给 Koa 实例使用
app.use(koaStatic('./static'))

用 koa-body 处理文件上传

本节目标: 使用 koa-body 实现文件上传接口, 处理文件上传

通过 koa-body 中间件,从请求体中读取客户端上传的二进制文件数据

通过使用 koa-body 中间件,不光能方便的获取请求体中的普通文本参数,也可获取二进制的文件数据,因此可以处理文件上传的场景。

使用步骤:

  1. 配置 koa-body,使其支持处理文件上传
// 引入 koa-body
const koaBody = require('koa-body')

// 调用 koaBody() 并进行文件上传处理相关的配置
app.use(koaBody({
    // 开启文件上传支持
    multipart: true,
  
    // 上传文件相关配置
    formidable: {
        // 文件上传到的目录
        uploadDir: './upload',
      
        // 保留上传文件的后缀名(默认为 false,所有上传的文件都会被去除后缀名)
        keepExtensions: true
    }
}))
  1. 在我们自己的中间件中,获取客户端通过 FormData 传递过来的文件及其他参数
app.use(async ctx => {
    // 获取上传的文件信息
    console.log('请求体中的文件', ctx.request.files)

    // 获取请求体中的其他参数
    console.log('请求体中的其他参数', ctx.request.body)

    ctx.body = 'Hello'
})

用 koa-router 实现后端路由

本节目标: 使用 koa-router 实现服务端路由

了解如何使用 koa-router 方便的实现服务端路由

自己实现不同的路由示例:

const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
  // 获取客户端请求的 URL 路径
  const url = ctx.url
  const method = ctx.method

  // 根据路径来判断具体要做的业务逻辑
  if (method === 'GET' && url === '/login') {
    ctx.body = '这是登录页'
  } else if (method === 'POST' && url === '/login') {
    ctx.body = '登录处理成功'
  } else if (method === 'GET' && url === '/register') {
    ctx.body = '这是注册页'
  } else if (method === 'POST' && url === '/register') {
    ctx.body = '注册处理成功'
  } else {
    ctx.body = '404 Not Found'
  }
})

app.listen(3000, () => {
  console.log('请访问 http://localhost:3000')
})

以上做法的弊端是:随着路由路径的增加,中间件代码变得很复杂。

而借助 koa-router 中间件,可以很清晰的创建和管理多个路由。

使用步骤:

  1. 安装依赖包
npm i @koa/router
  1. 引入 koa-router 并创建 Router 实例
// 引入 koa-router
const Router = require('@koa/router')

// 创建 Router 实例
const router = new Router()
  1. 在 Router 实例上创建路由处理器
// 静态路由 GET /login
router.get('/login', async ctx => {
    ctx.body = '这是登录页'
})

// 静态路由 POST /login
router.post('/login', async ctx => {
    ctx.body = '登录处理成功'
})

// 动态路由 GET /articles/123
router.get('/articles/:id', async ctx => {
    const id = ctx.params.id
    console.log(">>>>>>>> 动态路由参数 ID:", id);
    ctx.body = `ID 为 ${id} 的内容`
})
  1. 根据 router 生成路由相关的实际中间件函数,并设置给 Koa 实例
app.use(router.routes())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/769229.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Tekla Structures钢结构详图设计软件下载;Tekla Structures高效、准确的合作平台

Tekla Structures&#xff0c;它不仅集成了先进的三维建模技术&#xff0c;还融入了丰富的工程实践经验&#xff0c;为设计师、工程师和建筑商提供了一个高效、准确的合作平台。 在建筑项目的整个生命周期中&#xff0c;Tekla Structures都发挥着举足轻重的作用。从规划阶段开始…

朋友圈运营必备!一键转发和自动转发轻松搞定!

你还在手动发布多个微信号的朋友圈吗&#xff1f; 现在&#xff0c;就教你一招&#xff0c;让你轻松实现一键转发和自动转发朋友圈&#xff01; 首先&#xff0c;我们需要在个微管理系统上登录自己的微信号&#xff0c;以便进行统一管理。这个系统可以多个微信号同时登录&…

【长亭WAF(雷池)——网站保护之“动态防护”】

在当今的网络安全环境中&#xff0c;Web应用防火墙&#xff08;WAF&#xff09;扮演着至关重要的角色。 它们不仅能够防御常见的Web攻击&#xff0c;如SQL注入、跨站脚本攻击&#xff08;XSS&#xff09;等&#xff0c;还能够应对日益复杂的网络威胁。 作为业内领先的Web安全解…

苹果手机怎么刷机?适合小白的刷机办法!

自己的苹果手机用时间长了&#xff0c;有些人想要为自己的手机重新刷新一下&#xff0c;但又不知道怎么刷机。不要慌现在就来给大家详细介绍一下苹果手机怎么刷机&#xff0c;希望可以帮助到大家。 iPhone常见的刷机方式&#xff0c;分为iTunes官方和第三方软件两种刷机方式。 …

cv2.cvtColor的示例用法

-------------OpenCV教程集合------------- Python教程99&#xff1a;一起来初识OpenCV&#xff08;一个跨平台的计算机视觉库&#xff09; OpenCV教程01&#xff1a;图像的操作&#xff08;读取显示保存属性获取和修改像素值&#xff09; OpenCV教程02&#xff1a;图像处理…

代码随想录Day70(图论Part06)

108.冗余连接 题目&#xff1a;108. 冗余连接 (kamacoder.com) 思路&#xff1a;每次更新输出的边&#xff0c;来保证删除的是输入中最后出现的那条边。关键是&#xff0c;我要知道哪条边可以删除&#xff0c;而且是在join的时候就判断 尝试&#xff08;难得AC&#xff09; im…

gdbserver 指南

文章目录 1. 前言2. gdbserver 远程调试2.1 准备工作2.1.1 准备 客户端 gdb 程序2.1.2 准备 服务端 gdbserver2.1.3 准备 被调试程序 2.2 调试2.2.1 通过网络远程调试2.2.1.1 通过 gdbserver 直接启动程序调试2.2.1.2 通过 gdbserver 挂接到已运行程序调试 2.2.2 通过串口远程调…

WPF对象样式

基本样式设置 Style 设置指定对象的属性 属性&#xff1a; TargetType 引用在哪个类型上面&#xff0c;例如Button、Textblock。。 如果在控件对象里面设置Style&#xff0c;则TargetType必须指定当前控件名 只在作用域里面有效果&#xff0c;其他的相同控件没有影响&…

昇思25天学习打卡营第13天|ResNet50图像分类

1. 学习内容复盘 图像分类是最基础的计算机视觉应用&#xff0c;属于有监督学习类别&#xff0c;如给定一张图像(猫、狗、飞机、汽车等等)&#xff0c;判断图像所属的类别。本章将介绍使用ResNet50网络对CIFAR-10数据集进行分类。 ResNet网络介绍 ResNet50网络是2015年由微软…

Linux应用---内存映射

写在前面&#xff1a; 在进程间通信中&#xff0c;有一种方式内存映射。内存映射也是进程间通信的方式之一&#xff0c;其效率高&#xff0c;可以直接对内存进行操作。本节我们对内存映射进行学习&#xff0c;并结合案例进行实践。 1、基本理论 内存映射&#xff1a;是将磁盘文…

ODN网络弱光聚类定界与整治

01 ODN网络弱光运维现状 ODN网络是家庭宽带连接系统-无源光网络 (PON) 的重要组成部分&#xff0c;是连接局端 OLT 和用户 ONT 之间的光路通道&#xff0c;其质量直接影响整个PON系统的性能及可靠性。ODN光纤链路包括OLT PON口、ODF、主干光纤、一级分光器、分支光纤、二级分光…

登录功能和校验

基础版 controller package com.web.management.controller;import com.web.management.pojo.Emp; import com.web.management.pojo.Result; import com.web.management.service.EmpService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.anno…

如何用Vue3和Plotly.js绘制交互式漏斗图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Plotly.js 绘制漏斗图 应用场景 漏斗图常用于可视化业务流程中的各个阶段的转换率&#xff0c;例如销售漏斗或营销漏斗。它可以帮助用户识别流程中的瓶颈和改进机会。 基本功能 本代码使用 Plotly.js 库绘制…

【微机原理及接口技术】中断控制器8259A

【微机原理及接口技术】中断控制器8259A 文章目录 【微机原理及接口技术】中断控制器8259A前言一、介绍二、8259A的内部结构和引脚三、8259A的中断工作过程四、8259A的工作方式五、8259A的编程六、外部中断服务程序总结 前言 本篇文章将就8259芯片展开介绍&#xff0c;8259A的…

【多媒体】富客户端应用程序GUI框架 JavaFX 2.0 简介

JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架&#xff0c;它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能&#xff0c;旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出&#xff0c;2011 年 10 月发布了2.0 版本。JavaFX 2.0…

OpenLayers使用

初学ol&#xff0c;实现了高德地图不同图层的切换、交互性地图飞行以及加载本地JSON数据。 说一下不同图层切换的想法&#xff1a; 1.对于标准地图和卫星地图&#xff1a;二者最初便挂载到map上&#xff0c;两个图层是叠加显示的&#xff1b;当点击按钮时&#xff0c;其实是使…

VSCode里python代码不扩展/级联了的解决办法

如图 解决办法&#xff1a;重新下载新的扩展工具 步骤如下 1、在左边工具栏打开Extensions 2、搜索框输入python&#xff0c;选择别的扩展工具&#xff0c;点击Install - 3在扩展工具所在的目录下&#xff0c;新建一个文件&#xff0c;就可以用了

指定IP地址通过远程桌面访问WINDOWS10

1:登录Windows10系统&#xff0c;在控制面板找到系统和安全&#xff0c;打开Windows Defender防火墙。 2&#xff1a;点击感觉设置。 3&#xff1a;在入站规则中&#xff0c;找到远程桌面。查看自己的网络现在是公用&#xff0c;域&#xff0c;还是专用。选择对应的网络。 4&am…

Oracle EBS PO采购订单预审批状态处理

系统版本 RDBMS : 12.1.0.2.0 Oracle Applications : 12.2.6 问题症状: 采购订单状态:预审批 采购订单流程报错如下: po.plsql.PO_DOCUMENT_ACTION_AUTH.approve:90:archive_po not successful - po.plsql.PO_DOCUMENT_ACTION_PVT.do_action:110:unexpected error in acti…

js生成器,迭代器和可迭代对象详解

1.生成器函数和生成器 生成器函数是可以返回一个可迭代对象的特殊函数&#xff0c; 生成器是一个特殊的迭代器&#xff0c; 在js中可以使用function*来定义一个非连续执行的函数作为迭代算法&#xff0c; function* name() {yield value;yield value;yield value; }name: 函…