Flutter Web CORS解决方案2-代理转发协议

news2024/11/28 1:37:18

Flutter Web CORS解决方案2

    • local-cors-proxy
    • shelf_proxy
      • dart run shelf_proxy
      • flutter run --dart-define
      • wrap with shell
        • help & usage
        • mode & conf
        • run & debug
      • launch with proxy
        • vscode
        • Android Studio
      • 遗留问题

本文介绍第二种解决FlutterWeb CORS问题的方案:通过启动本地shelf_proxy服务代理协议cgi请求,并给出通过 vscode、AndroidStudio IDE 配置代理脚本快速启动调试的方法。


在 1-禁用浏览器安全策略 中,通过禁用chrome浏览器的安全策略或在浏览器中使用Allow-CORS插件,可以解决CORS问题。但浏览器中使用 Allow-CORS 插件访问时,仍存在部分协议OPTIONS预检跨域问题。
以上方案都是基于浏览器,对于企业微信H5页面应用的开发调试,其内置webView无法禁用安全策略,也无法启用Allow-CORS插件。
迫切需要支持移动终端通过 LAN IP 访问局域网内的web服务,以便调试企业微信内的实际布局渲染效果,及时发现和解决一些跨端兼容性问题。

Why does my http://localhost CORS origin not work?

local-cors-proxy

npm install Local CORS Proxy: npm install -g local-cors-proxy

Simple proxy to bypass CORS issues. This was built as a local dev only solution to enable prototyping against existing APIs without having to worry about CORS.

This module was built to solve the issue of getting this error:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disable

执行 npm ls -g --depth=0 或 npm ll -g --depth=0 可查看全局安装的 node_modules 目录。
可打开 node_modules/local-cors-proxy 文件夹查看 local-cors-proxy 代码:

  • 实现文件:lib/index.js
  • node命令行:bin/lcp.js

假设本地调试导致跨域问题(CORS issues)的 cgi 请求路径如下:

http://xxx.coding.net/api/qci/

CGI_HOST 为 xxx.coding.net,也记做 API_BASE_URL,也可能是 IP:PORT 模式。

执行 lcp --proxyUrl 启动:代理目标域名路径:

支持通过 -p(–port) 选项参数指定端口,默认端口为 8010。

$ lcp --proxyUrl http://xxx.coding.net

 Proxy Active 

Proxy Url: http://xxx.coding.net
Proxy Partial: proxy
PORT: 8010
Credentials: false
Origin: *

To start using the proxy simply replace the proxied part of your url with: http://localhost:8010/proxy

根据提示,修改代码 http.dart,将 baseUrl 中的目标域名(CGI_HOST)替换为 local-cors-proxy 代理服务 API_BASE_URL —— localhost:8010/proxy

http://localhost:8010/proxy/api/qci/

接下来,在命令行执行 flutter run -d 启动chrome调试,即经过代理服务请求 CGI 协议,绕过跨域。

  • flutter run -d chrome --web-renderer=html --web-port=8080

shelf_proxy

  • Flutter Web初尝试以及一些问题解决
  • Flutter 2 for Web 跨域问题
  • Flutter Web 跨域问题解决方案
  • Flutter Web 跨域请求踩坑笔记
  1. pubspec.yaml 中引入 shelf 依赖:

shelf_proxy 1.0.1 requires SDK version >=2.14.0 ❤️.0.0

  shelf: ^1.2.0
  shelf_proxy: ^1.0.1
  • shelf: A model for web server middleware that encourages composition and easy reuse
  • shelf_static: Static file server support for the shelf package and ecosystem
  • shelf_proxy: A shelf handler for proxying HTTP requests to another server
  • shelf_cors_headers: CORS headers middleware for Shelf
  1. 新建 scripts/proxy/shelf_lan_cgi_proxy.dart 文件:

支持传入启动参数 SHELF_PROXY_PORT 为 shelf_proxy 代理服务监听端口。
支持传入启动参数 SHELF_PROXY_DOMAIN 为被代理的 CGI 域名(CGI_HOST)。
configAccessControl 设置请求策略,以便允许跨域。实测只设置前两个即可?

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Credentials
// scripts/proxy/shelf_lan_cgi_proxy.dart
// dart run --define=SHELF_PROXY_DOMAIN=xxx.testing.coding.net
//          --define=SHELF_PROXY_PORT=8010 shelf_lan_cgi_proxy.dart

import 'dart:io';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_proxy/shelf_proxy.dart';

// 代理服务的地址(或域名)
// final String serveAddress = '127.0.0.1';
var serveAddress = InternetAddress.anyIPv6;
// 代理监听的服务端口
var listenPort = 8010;
// 需要代理的目标域名(默认测试环境)
var targetUrl = 'http://xxx.testing.coding.net';

// 设置请求策略,允许跨域
void configAccessControl(HttpServer server) {
  server.defaultResponseHeaders.add('Access-Control-Allow-Origin', '*');
  server.defaultResponseHeaders.add('Access-Control-Allow-Headers', '*');
  // server.defaultResponseHeaders.add('Access-Control-Allow-Methods', '*');
  // server.defaultResponseHeaders.add('Access-Control-Allow-Credentials', true);
}

Future main() async {
  // -D(--dart-define) 传参
  const proxyDomain = String.fromEnvironment('SHELF_PROXY_DOMAIN');
  if (proxyDomain.isNotEmpty) {
    targetUrl = 'http://$proxyDomain';
  }

  const proxyPort = int.fromEnvironment('SHELF_PROXY_PORT');
  if (proxyPort > 0) {
    listenPort = proxyPort;
  }

  var server = await shelf_io.serve(
    proxyHandler(targetUrl),
    serveAddress,
    listenPort,
  );

  configAccessControl(server);

  print('Shelf-Proxy @ http://${server.address.host}:${server.port}');
  print('Proxy Target Url: $targetUrl');
}

dart run shelf_proxy

  1. 执行 dart run shelf_lan_cgi_proxy.dart 命令,启动本地 shelf_proxy 代理服务。
  • dart run --define 传参 SHELF_PROXY_PORT 为代理监听端口,缺省为 8010;
  • dart run --define 传参 SHELF_PROXY_DOMAIN 为被代理的目标域名,缺省为 xxx.testing.coding.net;
$ dart run --define=SHELF_PROXY_DOMAIN=xxx.testing.coding.net --define=SHELF_PROXY_PORT=8010 scripts/proxy/shelf_lan_cgi_proxy.dart

Shelf-Proxy @ http://localhost:8010
Proxy Target Url: http://xxx.coding.net
  1. 修改 flutter web app 代码 http.dart,将 cgi 目标域名 apiBaseUrl(例如 xxx.coding.net)替换为代理服务 API_BASE_URL —— localhost:8010(LAN_IP:PORT):
// http.dart
baseUrl: 'http://localhost:8010/api/qci/',
  1. 执行 flutter run -d chrome 命令,启动 chrome 浏览器调试。
  • flutter run -d chrome --web-renderer=html --web-port=8080
  1. 如果要支持局域网访问调试,则可按以下步骤操作:
  • shelf_lan_cgi_proxy.dart 中的 serveAddress 已修改为 anyIP,可以是 localhost、127.0.0.1 或 192.168.0.106;
  • 执行 flutter run -d web-server 命令启动服务,指定 --web-hostname 0.0.0.0 为 anyIP:
    • flutter run -d web-server --profile --web-renderer html --web-port 8080 --web-hostname 0.0.0.0。
  • 这样,局域网内其他机器浏览器即可通过 LAN IP 地址链接(http://192.168.0.106:8080)访问服务。
  1. 思考:如何输出一些 proxyHandler 日志?

flutter run --dart-define

在上面第二步中,每次都要修改 http.dart 中写死的CGI域名(apiBaseUrl、APIBASEURL)、替换不同环境的认证token(authToken),这很不方便。

考虑将以上两个参数,抽出来由 flutter run 通过 --dart-define 传入参数,Dart 代码中调用 fromEnvironment 解析参数,替换占位变量 apiBaseUrlauthToken,如下图分支 ①。

wrap with shell

编写辅助启动 shelf_proxy 和 web app 的 Shell 脚本 launch_shelf.sh,主要功能是执行 dart run 启动代理、执行 flutter run 启动服务。

    # 从配置文件中读取配置
    get_env_config $mode $need_token

    # 兜底LAN IP和相关端口
    get_local_ipport

    if [ $role = server ]; then
        echo -e "✅  server listening on \033[4mhttp://$lan_ip:$web_port\033[0m"
    elif [ $role = proxy ]; then
        echo -e "✅  proxy listening on \033[4mhttp://$lan_ip:$proxy_port\033[0m"
    fi

    echo "------------------------------------------------------------"

    set -x

    if [ $role != proxy ]; then
        # 启动 shelf_proxy 代理(& 转移到后台)
        dart run --define=SHELF_PROXY_DOMAIN="${api_base_url:?unset or null}" --define=SHELF_PROXY_PORT=$proxy_port "$(dirname "$0")"/shelf_lan_cgi_proxy.dart &
        # 启动 client or server
        if [ $role = client ]; then
            flutter run --$mode -d chrome --web-renderer=html --web-port=$web_port --dart-define=API_BASE_URL="${lan_ip:?unset or null}":$proxy_port --dart-define=AUTH_TOKEN="${auth_token:?unset or null}"
        elif [ $role = server ]; then
            flutter run --$mode -d web-server --web-renderer=html --web-port=$web_port --web-hostname=0.0.0.0 --dart-define=API_BASE_URL="${lan_ip:?unset or null}":$proxy_port --dart-define=AUTH_TOKEN="${auth_token:?unset or null}"
        fi
    else
        # 启动 shelf_proxy 代理
        dart run --define=SHELF_PROXY_DOMAIN="${api_base_url:?unset or null}" --define=SHELF_PROXY_PORT=$proxy_port "$(dirname "$0")"/shelf_lan_cgi_proxy.dart
    fi

    set +x

    # 尝试杀死后台挂起的进程
    kill_run

执行 dart run shelf_lan_cgi_proxy.dart,启动 shelf_proxy 代理服务。

  • 从配置文件(config/debug.conf)中读取 CGI_HOST 到 api_base_url 传参给 dart run SHELF_PROXY_DOMAIN
  • 读取sh命令行参数 -s 存储到 proxy_port,传参给 dart run SHELF_PROXY_PORT

help & usage

执行 launch_shelf.sh -h 可查看脚本帮助:

$ ./scripts/proxy/launch_shelf.sh -h
launch_shelf.sh version: 1.0.0
Usage: launch_shelf.sh [-?hvCSdpr] [-i ip] [-w web-port] [-s shelf-port]

Options:
    -?,-h,--help            : show help and exit
    -v, --version           : show version and exit
    -C, --client            : start as client, default
    -S, --server            : start as server
    -P, --proxy             : start as proxy daemon
    -d, --debug             : run in debug mode, default
    -p, --profile           : run in profile mode
    -r, --release           : run in release mode
    -i, --ip ip             : set lan ip
    -w, --web-port port     : config flutter web port, default 8080
    -s, --shelf-port port   : config shelf proxy port, default 8010

主要涉及两组参数。

  1. 脚本启动角色(role):

    • -C 对应 flutter run -d chrome,启动web server,并拉起 chrome 运行;
    • -S 对应 flutter run -d web-server,启动web server,需要自行打开浏览器输入调试 url。
    • -P 只启动 shelf_proxy 代理,可搭配作为自行执行 flutter run 的代理使用,例如指定作为 vscode launch preLaunchTask 代理脚本。
    -C, --client            : start as client, default
    -S, --server            : start as server
    -P, --proxy             : start as proxy daemon
  • 代理模式(-P):可搭配作为自行执行 flutter run 的代理使用。

    • 外部基于 web server 监听端口访问 web 服务,web内部请求 cgi 经由 shelf_proxy 代理。
    • 这种模式目前主要用作指定作为 vscode launch preLaunchTask 代理脚本,参见下文。
  • 非代理模式(-C-S):sh 脚本还会执行 flutter run 启动 web app(-d chrome、-d web-server)。

    • 读取sh命令行参数 -w 作为 web_port。
    • flutter run 通过 --dart-define 传参 API_BASE_URL、AUTH_TOKEN。

    在 CS 模式中,dart run shelf_lan_cgi_proxy.dart 末尾需指定 & 转移到后台执行,避免阻塞,以便继续执行后续 flutter run 等命令。

  1. 运行模式(mode):-d调试模式、-p诊断模式、-r发布模式。

    • 可按需模拟调试某个环境的运行效果。
    • 在 get_env_config 函数中,根据运行模式读取对应的 token("$env_mode"_AUTH_TOKEN)。
    -d, --debug             : run in debug mode, default
    -p, --profile           : run in profile mode
    -r, --release           : run in release mode

mode & conf

脚本 aux_etc.sh 中定义的 get_env_config 函数,从配置文件 debug(profile,release).conf 中读取被代理的协议域名(CGI_HOST)和认证TOKEN(AUTH_TOKEN)。

conf 配置文件的 Shebang (#!/usr/bin/env bash)也申明为shell脚本,source导入后直接以 $var 形式引用变量,避免复杂的文本解析,方便处理。

由于 AUTH_TOKEN 涉及隐私和安全,故不再在conf中写死泄漏,改为读取环境变量("$env_mode"_AUTH_TOKEN),故请先在 zshrc 中申明导出三个环境的 AUTH_TOKEN:

# ~/.zshrc
export DEBUG_AUTH_TOKEN=  69c1********************************ccb4
export PROFILE_AUTH_TOKEN=2b57********************************fe89
export RELEASE_AUTH_TOKEN=2b57********************************fe89

无论是 -C 还是 -S 模式,–dart-define 的两个变量拼接如下,http.dart 中将解析这两个参数替换占位变量。

--dart-define=API_BASE_URL="${lan_ip:?unset or null}":$proxy_port
--dart-define=AUTH_TOKEN="${auth_token:?unset or null}"
  • 从脚本运行参数 -s 提取 proxy_port,作为 shelf_proxy 代理监听端口。
  • 主脚本的 main 函数,调用辅助脚本 aux_etc.sh 中的 get_env_config 函数,从 conf 中解析设置 auth_token
  • 主脚本的 main 函数调用 get_local_ipport 函数,调用 aux_etc.sh 中的帮助函数 get_lan_ip 解析获取 lan_ip

run & debug

在项目根目录执行 sh 脚本:

  1. 不指定角色,缺省 -C(-d chrome) 启动 client 模式,起好 web-server 之后,创建拉起 chrome 独立进程访问web服务。
$ ./scripts/proxy/launch_shelf.sh
  1. 指定角色 -S 启动 -d web-server 模式,点击提示中的 server listening 局域网链接打开浏览器即可访问web服务。

局域网中的其他机器,也可以输入该url访问服务。

$ ./scripts/proxy/launch_shelf.sh -S

✅  server listening on http://10.20.89.64:8080

  1. 指定角色 -P 启动纯代理模式,作为 vscode/Android Studio launch 的 preLaunchTask 任务,启动 proxy daemon。

launch with proxy

vscode/Android Studio 启动执行 main.dart,实际上是运行于 client 模式使用,相当于 flutter run -d chrome

故如果可以基于脚本或配置,在启动之前预启动 proxy daemon,并将监听的 IP:PORT 传给 flutter run --dart-define=API_BASE_URL,这样就可以实现 IDE 一键 launch with proxy,方便开发调试!

vscode

在 vscode 启动配置(.vscode/launch.json)中新建启动任务 debug - shelf

  • preLaunchTask 提前启动 tasks.json 中定义的 shelf_proxy 代理脚本——launch_shelf.sh。
  • 由于 json 无法读取环境变量,需要自行替换 API_BASE_URLAUTH_TOKEN

    关于局域网IP,可以执行 ./scripts/proxy/launch_shelf.sh -P 查看其输出的 proxy listening 信息。

// launch.json
    {
      "name": "debug - shelf",
      "request": "launch",
      "type": "dart",
      "program": "lib/main.dart",
      "flutterMode": "debug",
      "deviceId": "chrome",
      "args": ["--web-renderer=html", "--web-port=8080"],
      "toolArgs": [
        "--dart-define",
        "API_BASE_URL=LAN_IP:PROXY_PORT", // 局域网代理监听IP:PORT
        "--dart-define",
        "AUTH_TOKEN=DEBUG_AUTH_TOKEN"
      ],
      "preLaunchTask": "shelf_proxy - debug"
    },

注意:tasks.json 的 task config 中需指定 "isBackground": true,将代理服务运行于后台(等效命令行末尾置后运行的 &)。

// tasks.json
    {
      "label": "shelf_proxy - debug",
      "type": "shell",
      "command": "./scripts/proxy/launch_shelf.sh -P", // 默认代理端口为8010
      "group": "build",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "isBackground": true
    },

这样,在 vscode 侧边栏 - Run and Debug 就可以选择运行 debug - shelf,启动代理调试,解决跨域问题。

在这里插入图片描述

Android Studio

能否按照 vscode preLaunchTask 预启动 proxy 的思路,支持 Android Studio launch + proxy 呢?答案是肯定的,Android Studio 启动配置也支持指定 Before launch 任务,定义启动之前的操作。

工具栏 main.dart 下拉点选 Edit Configurations:

在这里插入图片描述

将打开 Run/Debug Configurations,Additional run args 为 --web-renderer=html --web-port=8080 --dart-define=API_BASE_URL=xxx.coding.net --dart-define=AUTH_TOKEN=69c1********************************ccb4

点击 Before launch ➕ Run External tool:

在这里插入图片描述

在打开的对话框中,点击➕ Create Tool,Program 右侧 Browse 打开点选 Finder 中的 scripts/proxy/launch_shelf_fuse.scpt,然后确认:

在这里插入图片描述

将 Additional run args 中的 API_BASE_URL 参数修改为局域网(LAN_IP):代理端口(PROXY_PORT):

关于局域网IP,可以执行 ./scripts/proxy/launch_shelf.sh -P 查看其输出的 proxy listening 信息。

在这里插入图片描述

如此设置确认后,点击Android Studio 工具栏绿色爬虫按钮(Debug ‘main.dart’),即可启动 launch with proxy。


思考:launch_shelf_fuse.scpt 为 Apple Script,封装启动 launch_shelf.sh -Pd,能否在 Program 直接指定启动 sh 呢?

-d 表示 debug, 还可指定 -p for profile、-r for release,注意填写对应环境的 AUTH_TOKEN。

#!/usr/bin/osascript

-- scpt dir
set cwd to quoted form of POSIX path of ((path to me as text) & "::")
do shell script "echo cwd = " & cwd
-- parent dir
set pcwd to do shell script "echo $(dirname " & cwd & ")"
do shell script "echo pcwd = " & pcwd
-- grandfather dir
set ppcwd to do shell script "echo $(dirname " & pcwd & ")"
do shell script "echo ppcwd = " & ppcwd

tell application "Terminal"
    do script "cd " & ppcwd & ";" & "./scripts/proxy/launch_shelf.sh" & space & "-P" & space & "-d"
    activate
end tell

问题是 Program 没法指定 sh 参数,且运行完 Before launch 任务,sh进程立即就会退出,无法运作为proxy daemon。

故这里写成 osascript,打开 Terminal 并使之 activate。这样 osascript 退出 Terminal 仍在,等效实现了proxy daemon。

遗留问题

目前发现构建详情页,点击切换到【构建物】tab,拉取构建物列表还是报 CORS error:

http://10.65.91.54:8010/api/qci/rest-api/totalresult/13819946/artifacts?page=1&ver=2

可能需要深入 shelf_proxy.dart 源码调试,分析一下具体原因。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Nodejs计算机毕业设计基于web的企业人事管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

Centos7下Samba服务器配置

环境 vm下centos7.6,IP地址:192.168.139.200 Samba概述 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文…

STM32H747AGI6技术、STM32H747AII6规格、STM32H747BGT6产品概述

产品概述:STM32H7高性能MCU基于高性能Arm Cortex-M7 32位RISC内核,工作频率高达400MHz。Cortex-M7内核具有浮点单元 (FPU) 精度,支持Arm双精度(符合IEEE 754标准)和单精度数据处理指令与数据类型。STM32H7 MCU支持全套…

第48篇 进阶(八) 3D绘图简介

导语 OpenGL是一个跨平台的用来渲染3D图形的标准API。在Qt中提供了QtOpenGL模块,从而很轻松地实现了在Qt应用程序中使用OpenGL,这主要是在QGLWidget类中完成的。因为3D绘图涉及到了专业方面的内容,我们下面只是讲解最简单的使用,…

Java基础之LinkedList

Java基础之LinkedList一、介绍二、add()一、介绍 底层是一个双向链表实现的List,内部每一个节点采用内部类Node表示,通过first、last引用分别指向链表的第一和最后一个元素非线程安全,可以用Collections.synchronizedList()方法对其进行包装…

Android入门第44天-Android里使用动态BroadCast

BroadCast是什么 BroadcastReceiver就是应用程序间的全局大喇叭,即通信的一个手段, 系统自己在很多时候都会发送广播,比如电量低或者充足,刚启动完,插入耳机,你有一条新的微信消息。。。这种都是使用Broad…

Windows实时运动控制软核(二):LOCAL高速接口测试之Qt

今天,正运动小助手给大家分享一下MotionRT7的安装和使用,以及使用Qt对MotionRT7开发的前期准备。 01 MotionRT7简介 MotionRT7是深圳市正运动技术推出的跨平台运动控制实时内核,也是国内首家完全自主自研, 自主可控的Windows运动…

redis的客户端

关系型数据库存储在磁盘当中&#xff0c;非关系型数据库存储在内存中 Jedis 第一步&#xff1a;导入依赖包 <dependencies><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</vers…

操作系统学习笔记

1.1 操作系统的概念、功能和目标 1.1.1 操作系统的功能和目标–系统资源的管理者 进程是一个程序的执行过程。执行前需要将该程序放到内存中&#xff0c;才能被CPU处理。 1.1.2 用户和计算机硬件之间的接口 联机命令接口交互式命令接口 脱机命令接口批处理命令接口 1.1.3…

点击化学标记试剂N3-PEG-DBCO,DBCO-PEG-azide,二苯并环辛炔聚乙二醇叠氮

N3-PEG-DBCO &#xff0c;DBCO PEG N3 &#xff0c;DBCO-PEG-azide&#xff0c;叠氮聚乙二醇环辛炔&#xff0c;二苯并环辛炔聚乙二醇叠氮产品规格&#xff1a; 1.分子量&#xff1a;1k&#xff0c;2k&#xff0c;3.4k&#xff0c;5k&#xff0c;10k&#xff0c;20k&#xff08…

百度地图三维盒子模型标注

效果图 利用百度地图mapv实现地图盒子模型标准 代码 function box() {var griddata [];for (var i 0; i < arr.length; i) {griddata.push({geometry: {type: Point,coordinates: arr[i]},properties: {count: Math.random() * (i 1) * 10000}});}var grid new mapvgl…

MySQL索引下推

1.什么是索引下推? 索引下推(Index Condition PushDown,简称ICP)是从MySQL5.6开始引入的一个特性,索引下推通过减少回表的次数来提高数据库的查询效率; 2.案例 准备: ①.为了演示索引下推,需要安装MySQL5.5和MySQL5.7两个版本的MySQL,因为索引下推是MySQL5.6版本中开始引入…

Java学习之断点调试

目录 应用场景 重要提示 定义 快捷键 运行图 案例1 案例2 案例3 案例4 练习题 第一题 题目 代码 toString方法 第二题 题目 应用场景 查找错误时&#xff0c;用断点调试一步一步的看源码执行的过程&#xff0c;从而发现错误所在 重要提示 在断点调试&#xff08;…

搭建hadoop单机环境

hadoop 笔记 sbin: 一些启动脚本 【服务端的 server bin】logs: 存放 hadoop 相关日志bin: 客户端的脚本etc: hadoop 相关的配置文件 格式化文件系统 配置免密码登录 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys# 启动…

Android DataBinding之布局中(layout)事件、运算逻辑、资源、工具类的使用与详解(七)

一、介绍 如果你学习了我前面的六篇文章&#xff0c;基本能够熟悉的处理data binding在开发过程的大多数业务&#xff0c;但是由于layout中的数据不一定满足UI上的效果&#xff0c;正常都是提前处理好数据&#xff0c;如果我们在layout引入中事件、运算逻辑、资源、工具类&…

【离散数学】代数系统 测试

1.判断题 代数系统中一个元素的左逆元一定等于该元素的右逆元。 正确答案&#xff1a; 错误 2.判断题 一个循环群的生成元不是唯一的。 正确答案&#xff1a; 正确 3.判断题 任何循环群必定是阿贝尔群&#xff0c;反之亦真。 正确答案&#xff1a; 错误 4.判断题 任何一个循环群…

gitlab-runner 的安装

Gitlab-ci说明 是GitLab内置的进行持续集成的工具&#xff0c;只需要在仓库根目录下创建.gitlab-ci.yml 文件&#xff0c;并配置GitLab Runner&#xff1b;每次提交的时候&#xff0c;gitlab将自动识别到.gitlab-ci.yml文件&#xff0c;并且使用Gitlab Runner执行该脚本 Gitl…

关于Redis数据库,我问了ChatGPT几个问题

最近互联网刮起了一阵ChatGPT风&#xff0c;从程序猿、产品经理、运营再到大学生&#xff0c;都在跟ChatGPT对话&#xff01;例如&#xff1a; 请帮我检查这段代码的BUG 请帮我设计一款功能像虹科VUZIX一样的智能AR眼镜 虹科Domo数据可视化工具有什么功能 帮我写一篇关于Weka并…

(C1)卷积层特点及torch.nn.Conv2d()

卷积层 文章目录卷积层一、常规卷积1.1 特点1.2 参数量 和 计算量二、可分离卷积2.1 逐深度卷积(Depthwise Convolution)2.2 逐点卷积(Pointwise Convolution)三、代码实现 ⭐一、常规卷积 参考资料 卷积神经网络之卷积层中的多输入多输出通道 卷积中参数量和计算量 有图文讲解…

数字孪生堆场集成箱的管理运维,可视化构建

为优化集装箱码头生产作业流程、提高生产效率&#xff0c;借鉴数字孪生在工业体系应用的经验&#xff0c;采用数字孪生技术对集装箱码头堆场这一典型的具有不确定性、多目标、复杂性的离散内部交通物流系统进行数字化运维&#xff0c;可显著提升作业效率。数字孪生技术正在成为…