当前位置: 首页 > news >正文

浏览器中的同源策略、CORS 以及相关的 Fetch API 使用

前言

笔者对前端 Web 技术的认真学习,其实开始于与 Fetch API 的邂逅。当时觉得 fetch() 的设计很不错,也很希望能够请求其它网站下的数据并作处理和展示。学习过程中 HTML 和 CSS 都还好说,由于几乎没有 Web 技术的基础,学习 Fetch API 的时候费了不少功夫,主要是其中涉及不少 HTTP 标头相关知识和习惯,也不理解 Fetch API 中很多属性和参数的意义或者为什么这么设计,更不必说 JavaScript 多种多样的版本和语法,以及十分重要的异步 I/O。

比如,在尝试中就遇到了 “blocked by CORS policy” 这样的错误。以访问 b23.tv 下的资源为例,Chrome 的提示是:

Access to fetch at ‘https://b23.tv/’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

说实话 Chrome 这个错误信息并不是很好,因为浏览器阻止该请求严格来说是出于 Same-origin policy (同源策略) 的限制,而 CORS policy (跨源资源共享策略) 提供了一种缓解同源策略限制的方法。由于当时对这些并不熟悉,根据关键字 CORS 寻找解决方案时也是一头雾水,不是很理解相关的原理和道理。相对来说,Firefox 的提示就好很多,还给出了相关链接共供参考。

Firefox's ERROR message said, Cross-Origin Request Blocked: the Same Origin Policy disallows reading the remote resource at ...

事后发现很多文章的内容如若用作学习,知识点之间联系不够紧密,又或者对于这些概念有所混淆,因此在本文中另作讲解,同时作为笔者学习的记录。文章中的内容主要来自 MDN 等网站,从英语翻译来,并在其中加入一些相关或必要的解释。

阅读本文需要了解一些基础 HTTP 知识(比如 HTTP 的方法和标头)、基本 URL 知识,以及 HTTPS 的基本概念。

这里吐槽一下某博主的 Fetch API 教程,且不说需要一定的 HTTP 知识或者 XHR 经验才能阅读,毕竟没有铺垫可以认为内容主要针对有经验的开发者,但是对于某些属性的解释就仅仅停留在解释上,甚至自己一知半解就去进行解释,我都很难相信作者是怎么说服自己的。有经验的人看到或许还能明白或者才出来在说什么,但对于新人来说,就是“前言不搭后语”。个人认为这样的内容对于新人来说完全没有帮助。因此,笔者不提倡、甚至反对“教程”式的教程。

同源策略 (Same-origin policy)

同源策略 (Same-origin policy) 是一项关键的安全机制,会限制从某一个 源 (Origin) 加载的文档或脚本,与来自其它源的资源之间的交互。

一个网络 (web) 上的资源 (或者说内容, content) 通常由 URL 来唯一标识,而该资源的 “源 (Origin)”,由其 URL 中的 scheme (即协议, protocol)、hostname (即域名, domain) 和端口号 (port) 三者所定义。三者必须全部相同,才能视作是同一个源。

浏览器在加载渲染显示网页时,会遵循同源策略。

同源策略可以帮助隔离开潜在的有害文档,减少可能的攻击手段 (attack vectors)。比如,这样可以使得攻击者无法利用钓鱼网站访问并转发用户登入的其它网站下的信息、用户所在内网环境中的资源,等等。

可以注意区分这种方式和 XSS 攻击的不同之处。

现代浏览器对于直接打开的计算中的文件 (即 file:/// 类型的 URL),一般将其视作来自于 “不透明源 (opaque origins)”。

“不透明 (opaque)” 指的是 “对该资源的上下文不可见”;笔者认为可将其理解为 “不可得知”。

也就是说,在浏览器中打开某一文件时,如果打开的文件引用了同目录下的其他文件,或者请求了其它资源,由于无法判断是否来自同一源,因此均会因违反同源策略而加载失败。有些浏览器会将同一目录及其子目录下的文件视作来自同一源,但这样做具有暴露用户信息的风险,比如当用户下载文件到默认目录并打开时,文件便有机会获知同一目录下其它文件的情况。

跨源网络访问

TL;DR: 简单来说,我们在浏览器中访问一个站点下的页面时,除了在页面上通过 嵌入 使用外部字体、外部 CSS 样式表,或者直接展示图片、媒体或者 <iframe>,而并不能 读取 来自其它源的内容进行进一步使用,除非其它源同意该源这么做。
 
举个例子,假如某个站点的资源或者 API 不想被其它站点直接在页面上获取并使用,那么同源策略会在默认条件下限制这种情况;相反,如果站点期望其它站点能够直接在页面上加载并使用自己的数据,则需要通过 CORS (参见后文) 进行相应的配置。

同源策略会限制不同源之间的交互,比如使用 fetch() 或者 <img> 标签时。通常来说,这些交互可以分为 3 类:

  • 跨源 (亦称 “跨域”) 写出 (writes) 通常被允许,比如外链 (links),页面重定向(redirects) 或者表单提交。其中一些 HTTP 请求需要事先经由 preflight 请求允许。
  • 跨源 嵌入 (embedding) 通常被允许。(请参见后续具体实例。)
  • 跨源 读取 (reads) 通常不被允许,但是由于 嵌入 的存在,常常也能一定程度上完成这一类交互。比如,所嵌入图像的维度是可以被读取的,所嵌入的脚本也会被执行(如 JSONP,所请求的脚本会调用某一个已经存在的函数,借以传递信息),甚至还可以通过某一嵌入资源是否可用来得知信息(比如,假如某网站根据用户是否登入决定资源是否可用,攻击者可借此得知用户是否在使用该网站)。

下面是一些可以跨源嵌入的资源的例子:

  • 使用 <script src="..."></script> 引入的 JavaScript。语法错误的具体错误信息仅对同源脚本可用。
  • 使用 <link rel="stylesheet" href="..."> 引用的 CSS。由于 CSS 宽松的语法规则,跨源的 CSS 需要具备正确的 Content-Type 标头。浏览器将阻止 MIME 类型不正确,且未以合法 CSS 规则开头的跨源 CSS 资源。
  • 使用 <img> 展示的图像。
  • 使用 <video><audio> 播放的媒体。
  • 使用 <object><embed> 嵌入的外部资源。
  • 使用 @font-face 应用的字体。有些浏览器允许跨源字体,有些则要求来自同源。
  • 使用 <iframe> 嵌入的任何内容。网站可以通过设置 X-Frame-Options 标头来组织跨源窗体嵌入。

使用 HTTP 中的 CORS (跨源资源共享) 可以允许跨源访问;通过 CORS,服务器可以向浏览器指明,允许从哪些 (除自身以外的) 源 (从自身) 加载内容,以此决定是否允许某个源对自己进行跨源访问。

而 (被跨源访问方) 若要阻止跨源访问:

  • 如要防止 (预期外的) 跨源写入,可以在请求中包含一个无法被猜测的口令并在服务器端校验 — 即 CSRF 口令 (CSRF token),来避免这种情况。

    CSRF (Cross-Site Request Forgery),即 “跨源请求伪造”。攻击者可通过向用户展示某个网站下的链接并诱导用户点击、展示表单并诱导用户提交,或直接通过内嵌图片(比如在电子邮件中内嵌图片)来让用户在不经意间请求指定的网址。这些情况下,用户向网站发送的请求并非出于自愿、或在知情条件下完成,而攻击者亦无须得知这些请求的内容,便可以让用户完成转账、下单等操作(如果网站没有针对这种情况进行判断的话)。

  • 如要防止资源被跨源读取,需要确保该资源不能被嵌入。因为资源被嵌入时总是会泄露出去或多或少的信息,所以保护资源不被跨源嵌入是必要的。

  • 为了防止资源被跨源嵌入,需要确保资源不能被用作 (解释为) 前文中列出的可嵌入格式。浏览器可能不会遵循 Content-Type 标头。比如,如果我们将 <script> 标签指向一个 HTML 文档,浏览器就会尝试将该 HTML 作为 JavaScript 来解析。如果该资源并不用于网站的入口,也可以使用 CSRF 口令来避免资源被他人跨源嵌入。

    比如某网站不希望自己站内的资源(如图片)被盗用,则需要进行举措来防止资源被跨源嵌入。由于浏览器在跨源请求时,默认会在 ReferrerOrigin 标头中附带当前页面的信息。服务器可以根据相关标头来判断如何返回内容。

同源策略 (Same-origin policy) 网页上还有关于跨源时的 JavaScript API 权限、跨源时数据存储相关的内容,有兴趣的读者请自行阅读,这里暂时不进行展开。

跨源资源共享 (CORS)

CORS (Cross-Origin Resource Sharing, 跨源资源共享) 是一项基于 HTTP 标头的机制,使得服务器能够向浏览器指明,可以允许浏览器从哪些除它本身之外的源加载 (它自身下的) 资源。

CORS 还依赖于浏览器的一种机制:浏览器会向跨源资源所在的服务器发送 “preflight” 请求 (译为 “预检请求”),以确认服务器是否会许可稍后的实际请求。浏览器会在 “preflight” 请求的标头中指示实际请求会使用的的 HTTP 方式,以及实际请求中使用的标头。

比方说,https://a.com 下的 JavaScript 代码想要使用 fetch() 请求 https://b.com/data.json,这就是一个跨源请求。而由于安全原因,浏览器会限制 JavaScript 发起的请求。比如 fetch()XMLHttpRequest 都遵循同源原则。这意味着,Web 应用默认只能加载使用和自身处于同一 Origin 下的数据,除非跨源的资源在标头中包含正确的 CORS 标头。

前文中已经阐述同源策略的目的和必要性,而通过 CORS (跨源资源共享) 机制,浏览器能发起安全的跨源请求、跨源加载资源。浏览器在 fetch()XMLHttpRequest 这些 API 中使用 CORS,以减少跨源请求带来的风险。

接下来将通过三种场景来演示 CORS 是如何工作的。所有示例都使用 fetch() 进行。

简单请求 (Simple requests)

TL;DR: 符合条件的跨源 简单请求 会被浏览器发出,服务器能够收到;但除非服务器允许,否则在客户端浏览器中,该请求的响应的 status, headers 以及 body 均无法 (在 JavaScript) 中读取,即 “不透明响应 (opaque requests)”。

有一些请求并不会触发 “preflight”,这些请求被称作 "简单请求" (simple requests)。这一术语来自已经不再使用的 CORS 技术规范,而新的 Fetch 技术规范 尽管定义了 CORS 但并未使用这一术语。

HTML 4.0 中的 <form> 表单元素能够向任何源提交简单请求(彼时尚无 fetch()XMLHttpRequest),因此人们撰写服务器程序时通常已经对 CSRF 作了应对处理。在这种假设下,服务器并不需要通过响应 preflight 来表明自己是否会处理某个形似表单提交的请求,因为 CSRF 带来的威胁,并不比表单提交这一行为本身所包含的威胁严重。

不过,如果网页脚本需要读取服务器响应的内容,仍然需要服务器通过 Access-Control-Allow-Origin 标头给予许可。

也就是说,跨源 简单请求 能够发出,被服务器接收到,但是如果服务器没有给出“授权”,则响应的内容无法被读取。

具体来说,一个 简单请求 需要满足以下所有条件:

  • 使用 GETHEADPOST 方法;
  • 除了用户代理 (user agent) 自动设置的标头 (如 Connection, User-Agent) 或 其它在 Fetch 规范中定义的禁用标头 外,只有 这些 Fetch 标准中定义为 CORS 安全的请求标头 允许手动设定: Accept, Accept-Language, Content-Language, Content-Type (另见后注),Range (只能包含一个简单范围区间标头值, 如 bytes=256-bytes=127-255)
  • 只允许这几种 类型/亚类型 组合作为 Content-Type 标头所指示的媒体类型: application/x-www-form-urlencoded, multipart/form-data, text-plain
  • 如果请求经由 XMLHttpRequest 发出,则 XMLHttpRequest.upload 属性返回的对象上不会注册事件监听器;也就是说,假设有一个 XMR 请求实例 xmr,则不会有代码调用 xhr.upload.addEvenListener() 添加事件监听器以监测上传过程。
  • 请求中不会使用 ReadableStream 对象。

以一个具体例子来说,假设 https://foo.example/page.html 处的内容想要获取 https://bar.other 域名下的 JSON 内容,则 foo.example 下部署的代码可能类似这样:

const fetchPromise = fetch("https://bar.other/data.json");
// 如果服务器会根据标头内容对同一 URL 响应不同内容,
// 需要记得设置对应的 Accept 标头fetchPromise.then((response) => response.json()).then((data) => {console.log(data);});

或者使用 await 而非 promise-chaining 的写法:

const response = await fetch("https://bar.other/data.json");
const data = await response.json();
console.log(data);

这样的操作会在客户端和服务器之间的进行简单的通信,赋权将使用响应中的 CORS 标头进行。

这里对于异步 I/O 编程相关的内容不作展开,仅讨论 CORS 相关的内容。

首先,fetch() 调用后,浏览器会向服务器发送类似这样的 HTTP 报文:

GET /data.json HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Referrer: https://foo.example/page.html

需要留意请求中的 Origin 标头 和 Referer 标头,前者表明请求来自 https://foo.example 这个源(用户代理会在跨源请求时带上这个标头),而后者则用来指示资源具体是从什么地址请求的。

服务器可以根据 Origin 标头来处理跨域请求,比如在响应中添加 Access-Control-Allow-Origin 标头,使得客户端可以读取该响应的内容。

也就是说,如果自己的服务涉及到 简单 跨源请求,需要在响应中设置相应的标头,以便 简单请求 的响应可以正常被读取 。如若想要访问来自不受自己控制的源的资源,且缺失相应的标头,则可以在自行将其代理后加以访问。

带有该标头的 HTTP 报文类似如下:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json{}

其中 Access-Control-Allow-Origin 标头的值为 * 通配符,表示允许任意源访问该资源。

如果将值设置为 https://foo.example,则表示仅允许 https://foo.example 通过 CORS 跨源访问自己的资源。

需要注意,对于 带有凭证数据的请求 (见后文),服务器必须在 Access-Control-Allow-Origin 标头中指定一个具体的 origin,而不能使用通配符 *.

在浏览器中使用 Fetch API 时,可以传入 RequestInit 对象进行一定的配置;这里只介绍几个相关的属性。

跨源请求时,对象的 mode 值默认为 cors,此时 Fetch API 便会根据 CORS 机制进行;此时如果请求为简单请求,由于不需要 preflight,会直接发出。但尽管请求会发出,如果 Access-Control-Allow-Origin 标头不满足,则会抛出错误。

需要注意,此时 Fetch API 会在请求中设置 Origin 标头。如果不希望暴露自己的来源,则可以参照下面的内容:

mode 可以设置为 no-cors(Chrome 会在上一点中提示使用这个参数,这一点比较不错),这时请求将不受 CORS 限制,并返回一个“不透明相应 (opaque response)”,但仍需要为 简单请求 — 如前所述,请求的标头会限制在 “CORS 安全请求标头”之中,且只能使用 GET, HEADPOST 方法。

注意这时的请求中不会带有 Origin 标头。

:笔者尚未测试强行设置为 * 的情况下是否仍然会返回“不透明响应”。

浏览器的请求默认会带上 referrer,网站可以通过 Referer 标头收集访客的浏览信息。如果不想暴露这个信息,则可以设置 RequestInit 对象的 referrerreferrerPolicy 参数。还可以通过设置 <meta> 标签控制 referrer policy,在请求嵌入的资源时不发送 Referer 标头。具体的选项和设置这里不多展开。

温馨提示: 如前所述,资源的跨源嵌入一般不受同源策略限制(比如引用图片),所以浏览器请求时不会发送 Origin 标头,但会带上 Referer 标头。比如,引用外链图片时,图片提供方可以根据 Referer 标头得知引用图片的站点,从而返回诸如“禁止盗图”之类的图片而非真正的图片资源。

Referer 标头的这个单词是错误拼写,而其它地方并没有这个错误。

预检请求

对于 “‘经过预检’ 的请求 (“preflighted” requests)”,浏览器会先使用 OPTIONS 方法请求跨源的资源,以便决定发出真正的请求是否安全。因为这些跨源请求可能会暴露用户数据,因此需要进行预检。

下面是一个会被进行预检的请求的例子:

const fetchPromise = fetch("https://bar.other/doc", {method: "POST",mode: "cors",headers: {"Content-Type": "text/xml","X-PINGOTHER": "pingpong",},body: "<person><name>Arun</name></person>",
});fetchPromise.then((response) => {console.log(response.status);
});

这个请求会创建一个 XML 格式的 body,并使用 POST 方法发送;此外,还设置了一个非标准的 HTTP 请求标头 X-PINGOTHER。类似这样的标头不是 HTTP/1.1 协议的一部分,但是对于 Web 应用程序来说一般很实用。

由于标头使用 text/xml 作为 Content-Type,并且设置了自定义标头,该请求会被进行预检。

预检请求类似这样:

OPTIONS /doc HTTP/1.1
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
...

其中,作为预检请求的一部分,Access-Control-Request-Method 用于通知服务器,实际请求将会使用 POST 方法;Access-Control-Request-Headers 则通知服务器,实际请求中的 X-PINGOTHER, Content-Type 标头会使用自定义的值。

服务器可以根据上述信息进行判断。假如服务器认为可以接受这样的请求,则返回类似这样的响应:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
...

其中 Access-Control-Allow-Methods 标头表示 POST, GET, OPTIONS 这些 HTTP 方法是可用的. 这有点类似 HTTP 405 响应时包含的 Allow 标头,只不过 Access-Control-Allow-Methods 被严格用于访问控制语境中。

此外,服务器返回值为 X-PINGOTHER, Content-TypeAccess-Control-Allow-Headers 的标头,表示允许实际请求使用这些标头。

最后 Access-Control-Max-Age 以秒为单位给出预检请求可被缓存使用的时间,其间不用再次发出预检请求。默认值为 5 秒。当下,事件最长可为 86400 秒。需要注意不同的浏览器会有自己的最大间隔值,假如 Access-Control-Max-Age 超过了该值,则优先使用浏览器自己的值。

预检请求完成后,浏览器便会进行真正的请求:

POST /doc HTTP/1.1
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF8
Origin: https://foo.example
...

服务器返回:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin

对于其中每个标头的具体作用和含义,这里不过多展开,可以访问上述的链接,或在 MDN 查询对应的标头。

需要注意,并不是所有的浏览器都支持跟随预检后实际请求的重定向。如果预检后的实际请求请求发生了重定向,部分浏览器会产生错误提示。最初,CORS 规定了需要这样做,但后续的更改不再具备这个要求。有些浏览器没有跟进这项变动,仍然遵循最开始的行为要求。

如果要支持这些未跟进的浏览器,除了修改服务端代码,使之不产生重定型,或更换为无需 preflight 的 简单请求 外,也可以在本地先使用 简单请求 得到重定向后的 URL,再向该地址请求。

但若请求包含 Authorization 标头(这也会触发 preflight),则上述的本地处理方式不再可用。

包含凭据信息的请求

CORS 和 fetch() 或 XMLHttpRequest 有意思的一项能力是,它发送 “包含凭据信息的 (credentialed)” 请求时,会考虑 HTTP cookies 以及 HTTP 认证信息。

默认情况下,浏览器中通过 fetch() 或 XMLHttpRequest 发出的请求中,不会包含凭据信息。

如果需要在 fetch() 发出的请求中包含凭据,则将 credentials 选项设为 "include"

如果需要在 XMLHttpRequest 发出的请求中包含凭据,则将 XMLHttpRequest.withCredentials 属性设为 true

假设 https://foo.example 下的内容,所请求的 https://bar.other 下的内容会设置 Cookies。

const url = "https://bar.other/resources/credentialed-content/";const request = new Request(url, { credentials: "include" });const fetchPromise = fetch(request);
fetchPromise.then((response) => console.log(response));

注意代码中将 credentials 选项设置为了 “include”。这是一个 简单 GET 请求,并不用进行预检,但是浏览器会拒绝任何不包含 Access-Control-Allow-Credentials: true 标头的响应,也不会使这些响应的内容对请求源可用。

浏览器和服务器之间的通信可能如下所示:

GET /resources/credentialed-content/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Referer: https://foo.example/examples/credential.html
Origin: https://foo.example
Cookie: pageAccess=2HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain[text/plain payload]

尽管请求的 Cookie 标头中,含有指向 https://bar.other 下内容的 cookie,但如果 bar.other 没有像示例中那样,在响应中包含值为 true 的 Access-Control-Allow-Credentials 标头,则该响应会被忽略,也不会为请求源可用。

预检请求与凭据信息

CORS 预检请求在任何时候都不应包含凭据信息。如果实际请求需要包含凭据信息,则服务器对预检请求的响应中需要指明 Access-Control-Allow-Credentials: true

对于凭据相关的请求,服务器不能使用 * 通配符,必须显式指明允许的源、标头、HTTP 方法等。

相关文章:

浏览器中的同源策略、CORS 以及相关的 Fetch API 使用

前言 笔者对前端 Web 技术的认真学习&#xff0c;其实开始于与 Fetch API 的邂逅。当时觉得 fetch() 的设计很不错&#xff0c;也很希望能够请求其它网站下的数据并作处理和展示。学习过程中 HTML 和 CSS 都还好说&#xff0c;由于几乎没有 Web 技术的基础&#xff0c;学习 Fe…...

爬虫 APP 逆向 ---> 粉笔考研

环境&#xff1a; 粉笔考研 v6.3.15&#xff1a;https://www.wandoujia.com/apps/1220941/history_v6031500雷电9 模拟器&#xff1a;https://www.ldmnq.com/安装 magisk&#xff1a;https://blog.csdn.net/Ruaki/article/details/135580772安装 Dia 插件 (作用&#xff1a;禁…...

2024河南萌新联赛第(三)场 河南大学

B. 正则表达式 题目&#xff1a; https://ac.nowcoder.com/acm/contest/87865/B 给出n个地址&#xff0c;每个地址的形式为x.x.x.x&#xff0c;找四个x都满足x>0&&x<255的个数 思路&#xff1a; 首先定义四个数组和一个字符&#xff0c;然后按题目所给的形式…...

回溯法---分割回文串

题目&#xff1a;给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是回文串。返回 s 所有可能的分割方案。 思路&#xff1a; 第一步&#xff1a;确定参数与返回值。参数为字符串s&#xff0c;分割起始下标startIndex&#xff0c;无返回值 第二…...

DDR等长,到底长度差多少叫等长?

DDR4看这一篇就够了 - 知乎 (zhihu.com) 【全网首发】DDR4 PCB设计规范&设计要点PCB资源PCB联盟网 - Powered by Discuz! (pcbbar.com) 终于看到较为权威的DDR4等长要求了: !!!! 依据这个要求&#xff0c;H616项目的等长线不合格&#xff1a;...

程序员面试题------N皇后问题算法实现

N皇后问题是一个著名的计算机科学问题&#xff0c;它要求在NN的棋盘上放置N个皇后&#xff0c;使得它们之间不能相互攻击&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上。这个问题可以看作是一个回溯算法问题&#xff0c;通过逐步尝试不同的放置位置&#xf…...

【C++学习】6、继承

1、什么是继承&#xff1f; 继承描述的是类与类之间的关系&#xff0c;A类继承B类&#xff0c;A类就拥有B类的数据和方法。 继承的方式&#xff1a; 公有继承&#xff08;public&#xff09; 保护继承&#xff08;protected&#xff09; 私有继承&#xff08;private&…...

从零开始的MicroPython(三) 按键与外部中断

上一篇&#xff1a;从零开始的MicroPython(二) GPIO及点灯代码 文章目录 前言硬件原理软件原理注意代码编写轮询外部中断其他 前言 点灯是嵌入式GPIO输出的典型&#xff0c;按键则是输入的典型。 硬件原理 按键对角接通。 软件原理 如果是一端接高电平&#xff0c;一端接单…...

Windows下编译安装Kratos

Kratos是一款开源跨平台的多物理场有限元框架。本文记录在Windows下编译Kratos的流程。 Ref. from Kratos KRATOS Multiphysics ("Kratos") is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, a…...

汽车-腾讯2023笔试(codefun2000)

题目链接 汽车-腾讯2023笔试(codefun2000) 题目内容 现在塔子哥有 n 个汽车&#xff0c;所有的汽车都在数轴上&#xff0c;每个汽车有1.位置 pos 2.速度 v &#xff0c;它们都以在数轴上以向右为正方向作匀速直线运动。 塔子哥可以进行任意次以下操作&#xff1a;选择两个汽车…...

软测面试二十问(最新面试)

1.软件测试的流程是什么 参加需求评审会&#xff0c;解决需求疑问---写测试用例---对测试用例进行评审---评审后开始执行测试---提交bug---追踪bug---关闭bug---回归测试---交叉测试---编写测试报告---冒烟测试 2.什么是黑盒测试和白盒测试&#xff1f;它们有何区别 黑盒测试…...

风吸杀虫灯采用新型技术 无公害诱虫捕虫

TH-FD2S】风吸杀虫灯利用害虫的趋光性和对特定波长的光源&#xff08;如紫外光、蓝光&#xff09;的敏感性&#xff0c;通过光波引诱害虫成虫扑灯。同时&#xff0c;内置的风扇产生强烈的气流&#xff0c;形成负压区&#xff0c;将害虫迅速吸入到收集器中。害虫在收集器内被风干…...

随手记录第十二话 -- JDK8-21版本的新增特性记录(Lambda,var,switch,instanceof,record,virtual虚拟线程等)

本文主要用于记录jdk8以来的新增特性及使用方法! 1.Java8 Lambda表达式(8) 1.1 方法引用 List<String> list List.of("1", "2", "3");list.forEach(i -> System.out.println(i));//方法引用list.forEach(System.out::println);1.2 接…...

SpringCloud网关 SpringBoot服务 HTTP/HTTPS路由/监听双支持

背景 一般来说SpringCloud Gateway到后面服务的路由属于内网交互&#xff0c;因此路由方式是否是Https就显得不是那么重要了。事实上也确实如此&#xff0c;大多数的应用开发时基本都是直接Http就过去了&#xff0c;不会一开始就是直接上Https。然而随着时间的推移&#xff0c…...

JavaScript做网页是否过期的处理

通过路由上的参数生成唯一md5和路由上token做验证_md5 token-CSDN博客 前言&#xff1a;基于这篇文章我们做网页是否超时&#xff0c;网页是否过期的处理。打开一个网页允许他在一定时间内可以访问&#xff0c;过了这个时间就不可以访问了&#xff0c;encrypt是h5加密方法&…...

python coding时遇到的问题

Q&#xff1a;只有cpu的时候加载模型 A&#xff1a;checkpoint torch.load(model_path, map_locationtorch.device(‘cpu’)) Q&#xff1a;vscode的文件路径和spyder的不一样 A&#xff1a;在vscode中&#xff0c;右键要用的文件&#xff0c;选择“文件相对路径”...

攻防演练号角吹响,聚铭铭察高级威胁检测系统助您零失分打赢重保攻坚战

在数字化浪潮中&#xff0c;攻防演练成为了衡量网络安全防御力的核心标尺&#xff0c;其重要性与日俱增。这项由政府、行业监管或企业内部主导的安全活动&#xff0c;随着互联网普及而兴起&#xff0c;现已发展成为全球公认的检验网络安全体系效能的标准。它不仅关乎技术实力的…...

个人量化交易兴起!有什么好用的量化软件推荐?迅投QMT量化平台简介!

QMT是专门为机构、活跃投资者、高净值客户等专业投资者研发的智能量化交易终端&#xff0c;拥有高速行情、极速交易、策略交易、多维度风控等专业功能&#xff0c;满足专业投资者的特殊交易需求。覆盖业务范围广:沪深A股、港股通、两融、期权、期货。 适合用QMT的投资者&#x…...

SQL labs-SQL注入(七,sqlmap对于post传参方式的注入,2)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。参考&#xff1a;SQL注入之Header注入_sqlmap header注入-CSDN博客 序言&#xff1a; 本文主要讲解基于SQL labs靶场&#xff0c;sqlmap工具进行的post传参方式的SQL注入&#xff0c…...

SAM 2: Segment Anything in Images and Videos

Introduction 提出的目的&#xff1a; 1.现有的应用像自动驾驶&#xff0c;AR等来说都是需要temporal localization beyond image-level segmentation&#xff08;时序定位而不仅是图片分割&#xff09; 2. 一个好的分割模型不应该仅仅局限于图片领域&#xff0c;而是图视频两…...

软件测试面试,如何自我介绍?

又是一年金九银十&#xff0c;相信不少小伙伴都在准备跳槽面试&#xff0c;而面试中一个必不可少的环节就是自我介绍&#xff0c;所以&#xff0c;今天我们就来聊一聊软件测试面试中如何自我介绍。 为什么要自我介绍 在讨论如何自我介绍之前&#xff0c;我们先来讨论一下为…...

力扣第四十七题——全排列II

内容介绍 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],…...

Springer旗下中科院2区TOP,国人优势大!

关注GZH【欧亚科睿学术】&#xff0c;第一时间了解期刊最新动态&#xff01; 1 通信网络类 【期刊简介】IF&#xff1a;4.0-5.0&#xff0c;JCR1区&#xff0c;中科院3区 【出版社】ELSEVIER出版社 【检索情况】SCIE&EI双检&#xff0c;CCF-C类 【征稿领域】通信网络的…...

【C++】C++入门知识详解(下)

大家好~我们接着【C】C入门知识详解&#xff08;上&#xff09;-CSDN博客来介绍另一些C入门基础知识。 1.缺省值和缺省参数 缺省参数就是声明或定义函数时为函数的参数指定一个缺省参数。在调用该函数时&#xff0c;如果没有指定实参&#xff0c;则采用该形参的缺省值&#xf…...

分压电阻方式的ADC电压校准

无人机有个流程是电池电压校准。具体做法是:让你用万用表测量一下电池两端的电压,然后输入到文本框中,电机计算能重新计算出电压分压器的值,从而获得电池电压值。 这种方法实现的原理是这样的: 电阻分压检测电压原理,以上图为例: 当电路确定时,R2/(R1+R2)是一个定值R,…...

使用Postman测试API短轮询机制:深入指南

短轮询是一种Web开发中常用的技术&#xff0c;用于在客户端和服务器之间定期检查更新。与长轮询或WebSockets等技术相比&#xff0c;短轮询简单易实现&#xff0c;但可能带来较多的HTTP请求&#xff0c;从而增加服务器负担。Postman作为一个强大的API测试工具&#xff0c;可以用…...

明清进士人数数据

明清进士人数数据 指标&#xff1a;省份名称、城市名称、区县名称、明清各省进士人数、明清各城市进士人数、明清各县区进士人数 指标说明&#xff1a; Province[省份名称]-统计数据所属省份 City[城市名称]-统计数据所属地级市 Region[区县名称]-统计数据所属区县 MQpro…...

C# 串口通信(通过serialPort控件发送及接收数据)

连接串口 界面设计打开串口发送数据通过文件发送发送数据 接收数据 首先可以在 工具箱中搜索serialport&#xff0c;将控件拖到你的Winfrom窗口。 界面设计 打开串口 private void Connect_Click(object sender, EventArgs e){serialPort1.PortName comboBox2.Text;//端口名s…...

数据安全的新盾牌:SQL Server数据库镜像技术详解

数据安全的新盾牌&#xff1a;SQL Server数据库镜像技术详解 在数据驱动的商业世界中&#xff0c;数据库的安全性是维护企业运营的关键。SQL Server提供了多种数据保护机制&#xff0c;其中数据库镜像技术是一个强大的高可用性解决方案&#xff0c;它可以显著提高数据的安全性…...

【C语言版】数据结构教程(一)绪论(上)

【内容简介】本文整理数据结构&#xff08;C语言版&#xff09;相关内容的复习笔记&#xff0c;供各位朋友借鉴学习。本章内容更偏于记忆和理解&#xff0c;请读者们耐心阅读。 数据结构教程 绪论&#xff08;上&#xff09; 本节学习目标 1.1 基本概念 1.2 抽象数据类型的表示…...

做网站前端有前途么?/疫情最新情况

最近有客户提出一个比较有意思的问题&#xff0c;生产环境与测试环境数据量相差比较大&#xff0c;导致两个环境中执行路径大不相同&#xff0c;如何能保证这两个环境执行计划相同呢&#xff1f;这还是一个比较实际的需求&#xff0c;MySQL中没有绑定执行计划功能&#xff0c;并…...

nba东西部最新排名/宁波网站推广优化公司怎么样

//程序作者:管宁 //站点:www.cndev-lab.com //所有稿件均有版权,如要转载,请务必著名出处和作者 #include <iostream> using namespace std; class Vehicle { public: Vehicle(int weight 0) { Vehicle::weight weight; } void SetWeight(int we…...

做网站做注册登录的难点/网络营销的企业有哪些

1. vi与vim的关系 在windows下的默认编辑器是记事本&#xff08;notepad&#xff09;&#xff0c;然而功能太low&#xff0c;所以我一般使用的是notepad这个文本编辑器软件。可以类比得到&#xff0c;vi是linux的默认编辑器&#xff0c;vim则是其升级版本&#xff0c;vim是推荐…...

公司做影视网站侵权/百度seo霸屏软件

原标题&#xff1a;iOS便签如何实现扫描二维码界面功能这是一款多功能便签软件工具&#xff0c;有“二维码”功能&#xff1a;它支持用户将便签内容制作成二维码&#xff0c;然后通过敬业签app扫描该二维码&#xff0c;显示相应的便签内容。那么&#xff0c;如何扫描便签二维码…...

做平面免费接单网站/品牌网络营销案例

map:数据的插入 在构造map容器后&#xff0c;我们就可以往里面插入数据了。这里讲三种插入数据的方法&#xff1a;第一种&#xff1a;用insert函数插入pair数据map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1,“student_one”)); 第二种&…...

盘锦如何做百度的网站/网站优化招商

Docker 修改容器端口 本文介绍如何修改容器端口 对于已经创建的容器&#xff0c;可以通过下面的方法修改端口&#xff1a; 将容器提交为镜像&#xff0c;重新运行修改容器配置文件 将容器提交为镜像&#xff0c;重新运行 略 修改容器配置文件 修改前需要关闭docker&…...