同源政策与CORS

news2025/1/23 7:03:17

CORS意为跨源资源共享(Cross origin resource sharing),它是一个W3C标准,由一系列HTTP Header组成,这些 HTTP Header决定了浏览器是否允许JavaScript 代码成功获得跨源请求的服务器响应

在说CORS之前,先说一下关于浏览器的同源政策(same-origin policy)。

同源政策是浏览器安全的基石,由Netscape公司引入浏览器,目前所有浏览器都实行这个政策。最初它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同":协议相同,域名相同,端口相同。
举例来说,http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)。它的同源情况如下:

http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)

同源政策的是为了保证用户信息的安全,防止恶意的网站窃取数据。设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。

由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。

(1) Cookie、LocalStorage 和 IndexDB 无法读取。

(2) DOM 无法获得。

(3) AJAX 请求不能发送。

虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。所以有时需要一些额外的操作来打破同源政策的束缚。


Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同时,浏览器允许通过设置document.domain共享 Cookie。

举例来说,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。

document.domain = 'example.com';

现在,A网页通过脚本设置一个 Cookie。

document.cookie = "test1=hello";

B网页就可以读到这个 Cookie。

var allCookie = document.cookie;

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策。

另外,服务器也可以在设置Cookie的时候,可以指定Cookie的所属域名为一级域名,比如:

Set-Cookie: key=value; domain=.example.com; path=/

这样的话,二级域名不用做任何设置,都可以读取这个Cookie。


同源政策规定,AJAX请求只能发给同源的网址,否则就报错。有三种方法规避这个限制:JSONP、WebSocke和CORS。
JSONP是早期服务器与客户端跨源通信的常用方法。它的基本思想是,通过在网页上添加一个<script>元素向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

上面代码通过动态添加<script>元素,向服务器example.com发出请求。该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

foo({
  "ip": "8.8.8.8"
});

由于<script>元素请求的脚本,直接作为代码运行。这时只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

下面是浏览器发出的WebSocket请求的头信息

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

上面请求头中有一个字段是Origin,声明了该请求的源。正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。服务器可以根据这个字段,判断是否许可本次通信。如果允许这个源,服务器就会做出如下回应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

接下来就是CORS了。CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准, 堪称跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。

同源安全策略默认阻止“跨源”获取资源,XMLHttpRequest 和 Fetch API 都遵循同源策略,这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源。

CORS 机制的图表表示

现代浏览器支持在API容器中(例如 XMLHttpRequest 或 Fetch)使用 CORS,CORS 机制给了WEB服务器一种权限,允许服务器进行跨源访问控制。服务器可以选择在响应报文中包含正确的CORS响应头,这样浏览器就能允许JavaScript跨源访问WEB服务器提供的资源。

CORS功能概述
CORS标准新增了一组 HTTP Header字段,允许服务器声明哪些源(Origin)通过浏览器有权限访问。另外,标准要求对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预请求(preflight request),获知服务器端是否允许该跨源请求。服务器确认允许后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端是否需要携带身份凭证(Credential,例如 Cookie 和 HTTP 认证相关数据)。CORS请求失败时会产生错误,但是为了安全,在JavaScript代码层面无法获知到底具体是哪里出了问题。只能查看浏览器的控制台以得知具体是哪里出现了错误。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。AJAX 的跨域设计就是,只要表单可以发,AJAX 就可以直接发

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中增加一个Origin字段。

简单 GET 请求的示意图

下面是一个浏览器发送跨源AJAX请求是简单请求例子:

GET /resources/public-data/ 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

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。而服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。如果Origin指定的域名在许可范围内,服务器返回的响应会包含Access-Control-Allow-Origin头信息字段

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/xml

[…XML Data…]

本例中,服务端返回的标头Access-Control-Allow-Origin: * 表明,该资源可以被任意外源访问。

使用 Origin 和 Access-Control-Allow-Origin 就能完成最简单的访问控制。如果 https://bar.other 的资源持有者想限制他的资源只能通过https://foo.example来访问(也就是说,非 https://foo.example 域无法通过跨源访问访问到该资源),可以这样做:

Access-Control-Allow-Origin: https://foo.example

注意: 当响应的是附带身份凭证的请求时(credentialed requests request),服务端必须明确 Access-Control-Allow-Origin 的值,而不能使用通配符“*”(后面还会再说明)。

上面的头信息之中除了Access-Control-Allow-Origin是必须的字段,还有两个可选的字段Access-Control-Allow-Credentials和Access-Control-Expose-Headers。

Access-Control-Allow-Credentials字段的值是一个布尔值,表示是否允许发送Cookie。默认情况下Cookie不包括在CORS请求之中。Access-Control-Allow-Credentials设为true,表示服务器明确许可Cookie可以包含在请求中发给服务器。这个值也只能设为true,如果服务器不允许浏览器发送Cookie,删除该字段即可。

CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到响应头中的6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定,例如:

Access-Control-Expose-Headers: FooBar

这样XMLHttpRequest对象的getResponseHeader('FooBar')可以返回FooBar的值。

withCredentials 属性
上面说到CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器指定Access-Control-Allow-Credentials: true,另一方面开发者必须在AJAX请求中打开withCredentials属性。

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

否则,即使服务器同意发送Cookie,浏览器也不会发送。

但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials。

xhr.withCredentials = false;

非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前增加一次使用 OPTIONS 方法发起的预检请求(preflight request)到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用可以避免跨域请求对服务器的用户数据产生未预期的影响。

预检请求会询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP方法和请求头字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

如下是一个需要执行预检请求的 HTTP 请求:

const xhr = new XMLHttpRequest();
xhr.open("POST", "https://bar.other/resources/post-here/");
xhr.setRequestHeader("X-PINGOTHER", "pingpong");
xhr.setRequestHeader("Content-Type", "application/xml");
xhr.onreadystatechange = handler;
xhr.send("<person><name>Arun</name></person>");

上面的代码使用 POST 请求发送一个 XML 请求体,该请求的 Content-Type 为 application/xml,且使用了一个自定义的X-PINGOTHER 请求头。浏览器发现这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。

下面是这个"预检"请求的HTTP头信息。

OPTIONS /doc 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
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。OPTIONS 是 HTTP/1.1 协议中定义的方法,用于从服务器获取更多信息,是安全的方法。该方法不会对服务器资源产生影响。OPTIONS预检请求中除了origin之外同时携带了下面两个标头字段:

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。服务器据此决定,该实际请求是否被允许。

服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,若确认允许跨源请求,就可以做出如下回应。

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

服务器的响应头携带了 Access-Control-Allow-Origin: https://foo.example,限制请求的源域。Access-Control-Allow-Methods 表明服务器允许客户端使用 POST 和 GET 方法发起请求。Access-Control-Allow-Headers 表明服务器允许请求中携带字段 X-PINGOTHER 与 Content-Type。与 Access-Control-Allow-Methods 一样,Access-Control-Allow-Headers 的值为逗号分割的列表。最后,字段 Access-Control-Max-Age 给定了该预检请求可供缓存的时间长短,单位为秒,默认值是 5 秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。以上例子中,该响应的有效时间为 86400 秒,也就是 24 小时。请注意,浏览器自身维护了一个最大有效时间,如果该标头字段的值超过了最大有效时间,将不会生效。当然此时服务器也可以有可选的Access-Control-Allow-Credentials: true响应头,含义与简单请求时是一样的。

如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。

预检请求完成之后,发送实际请求就跟简单请求一样,会有一个Origin头信息字段(当然也会包含预检请求中已经说明过的自定义请求头等内容)。服务器的回应也都会有一个Access-Control-Allow-Origin头信息字段。

POST /doc 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
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache

<person><name>Arun</name></person>

服务器的响应:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Vary: Accept-Encoding, Origin

Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some XML payload]

这里有一个Vary响应头。Vary响应头就是让同一个URL根据某个请求头的不同而使用不同的缓存。这里的设定是让浏览器在即使同一个URL的情况下,也能根据不同的Accept-Encoding或Orign进行不同的缓存。为什么要有这个设定?因为默认浏览器里的缓存是以URL为key,一个 URL 对应一个缓存。但如果浏览器访问了两 URL相同但CORS响应头不应该相同的资源会如何呢?

比如在同一个浏览器下,先打开了foo.taobao.com上的一个页面,访问了服务器的资源,这个资源和URL被浏览器缓存了下来,与资源内容一起缓存的还有Access-Control-Allow-Origin: https://foo.taobao.com响应头。这时又打开 bar.taobao.com上的一个页面,这个页面也访问服务器上之前的那个资源,因为URL相同,这时它会读取本地缓存。但是读到的 Access-Control-Allow-Origin头信息是缓存下的 https://foo.taobao.com 而不是自己想要的 https://bar.taobao.com,这时浏览器就报跨域错误了,虽然它应该是能访问到这份资源的。再比如用户先访问了foo.taobao.com的一个页面 A,页面 A 里用<img>标签加载了一张图片,注意这时候这张图片已经被浏览器缓存了,并且缓存里没有 Access-Control-Allow-Origin响应头,因为<img>发起的请求不带Origin请求头,然后用户又访问了foo.taobao.com的另一个页面 B,页面 B 里用 XHR 请求同一张图片,结果读了缓存,没有发现 CORS 响应头,浏览器报跨域错误。

在CORS的场景下,使用Vary: Origin来保证从不同网站发起的请求可以使用各自的缓存。比如从foo.taobao.com发起的请求缓存中的响应头是:

Access-Control-Allow-Origin: https://foo.taobao.com
Vary: Origin

的话,bar.taobao.com在发起同URL的请求就不会使用这份缓存了,因为Origin请求头变了。

还有<img>标签发起的非 CORS 请求缓存中的响应头是:

Vary: Origin

的话, 在使用 XHR 发起的 CORS 请求也不会使用那份缓存,因为Origin请求头从无到有,也算是变了。

最佳的实践原则是:

If CORS protocol requirements are more complicated than setting `Access-Control-Allow-Origin` to * or a static origin, `Vary` is to be used.

如果你的 Access-Control-Allow-Origin响应头不是简单的写死成了*或者某一个固定的源,那么你就应该加上Vary: Origin响应头。

最后再重复说明一下前面已经提及过的附带身份凭证(credential)的请求。

对于跨源的XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest对象的 withCredentials标志为true,或在构造 Request 对象时设置。

本例中https://foo.example 的某脚本向 https://bar.other 发起一个 GET 请求并设置 Cookies。在 foo.example 中可能包含这样的 JavaScript 代码:

const invocation = new XMLHttpRequest();
const url = "https://bar.other/resources/credentialed-content/";

function callOtherDomain() {
  if (invocation) {
    invocation.open("GET", url, true);
    invocation.withCredentials = true;
    invocation.onreadystatechange = handler;
    invocation.send();
  }
}

将 XMLHttpRequest 的 withCredentials 标志设置为 true才能向服务器发送 Cookies。这是一个简单 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=2

请求中指定了 Cookie 是属于 https://bar.other 的内容。如果来自服务器的响应中缺失 Access-Control-Allow-Credentials: true,则服务器响应内容会被浏览器忽略,不会提供给请求的发送者。

服务器的响应:

HTTP/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]

CORS 预检请求不能包含凭据,但对预检请求的响应头中必须指定 Access-Control-Allow-Credentials: true 来表明可以携带凭据进行实际的请求。

在服务器响应附带身份凭证的请求时:

  • 服务器不能将 Access-Control-Allow-Origin 的值设为通配符“*”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com。
  • 服务器不能将 Access-Control-Allow-Headers 的值设为通配符“*”,而应将其设置为请求头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  • 服务器不能将 Access-Control-Allow-Methods 的值设为通配符“*”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

另外,上面的响应标头中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改(修改pageAccess的内容)。如果操作失败,将会抛出异常。同样的,如果用户设置其浏览器拒绝所有第三方 cookie,那么将不会被保存。

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

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

相关文章

多功能租车平台微信小程序源码 汽车租赁平台源码 摩托车租车平台源码 汽车租赁小程序源码

多功能租车平台微信小程序源码是一款用于汽车租赁的平台程序源码。它提供了丰富的功能&#xff0c;可以用于租赁各种类型的车辆&#xff0c;包括汽车和摩托车。 这个小程序源码可以帮助用户方便地租赁车辆。用户可以通过小程序浏览车辆列表&#xff0c;查看车辆的详细信息&…

浙大陈越何钦铭数据结构07-图6 旅游规划

题目: 有了一张自驾旅游路线图&#xff0c;你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序&#xff0c;帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的&#xff0c;那么需要输出最便宜的一条路径。 输入…

汽车电子笔记之:AUTOSA架构下的OS概述

目录 1、实时操作系统&#xff08;RTOS&#xff09; 2、OSEK操作系统 2.1、OSEK概述 2.2、OSEK处理等级 2.3、OSEK任务符合类 2.4、OSEK优先级天花板模式 3、AUTOSAR OS 3.1、 AUTOSAR OS对OSEK OS的继承和扩展 3.2、AUTOSAR OS的调度表 3.3、AUTOSAR OS的时间保护 3…

PID直观感受简述

0、仿真控制框图 1、增加p的作用&#xff08;增加响应&#xff09;P 2、增加I的作用&#xff08;消除稳差&#xff09;PI 3、增加D的作用&#xff08;抑制波动&#xff09;PID 加入对噪声很敏 4、综合比对

java maven项目打jar包发布(精简版)

目录 一、maven打包 二、安装jdk环境 三、安装mysql 四、jar包传输到服务器 一、maven打包 先clean再package target文件夹下面有生成一个jar包 二、安装jdk环境 1、下载jdk cd /usr/local wget https://repo.huaweicloud.com/java/jdk/8u201-b09/jdk-8u201-linux-x64.tar.…

[谦实思纪 02]整理自2023雷军年度演讲——《成长》(下篇)创业之旅(创业与成长)

文章目录 [谦实思纪]整理自2023雷军年度演讲 ——《成长》&#xff08;下篇&#xff09;创业之旅&#xff08;创业与成长&#xff09;0. 写在前面1. 创业&#xff01;&#xff08;创业与成长&#xff09;1.1 找互补的朋友一起干&#xff0c;更容易成功1.2 创业中必须要有领导者…

Verilog 基础语法(题目)

Verilog 基础语法&#xff08;题目&#xff09; **本内容来自 牛客网Verilog基础语法** 1、四选一多路器 制作一个四选一的多路选择器&#xff0c;要求输出定义上为线网类型 状态转换&#xff1a; d0 11 d1 10 d2 01 d3 00 信号示意图&#xff1a; 波形示意图&#xff1a; …

抖音seo矩阵系统源代码开发部署分享

一、 开发步骤分享 抖音SEO矩阵系统源代码开发部署分享&#xff0c;需要经验丰富的开发人员和服务器管理人员&#xff0c;以下是大致的步骤&#xff1a; 确定你需要的功能和设计&#xff0c;确定开发人员和设计师的角色和任务分配&#xff0c;以及开发进度和计划。 确定服务器…

分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测

分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测 目录 分类预测 | MATLAB实现MIV-SVM的平均影响值MIV算法结合支持向量机分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 先利用平均影响值MIV算法对特征进行排序&#xff0c;确定分类特征…

SimpleDateFormat 是线程安全的吗?使用时应该注意什么?面试回答

面试回答 在日常开发中&#xff0c;我们经常用到时间&#xff0c;我们有很多办法在 Java 代码中获取时间。但是不同的方法获取到的时间的格式都不尽相同&#xff0c;这时候就需要一种格式化工具&#xff0c;把时间显示成我们需要的格式。 最常用的方法就是使用 SimpleDateForm…

leetcode 718. 最长重复子数组

2023.8.24 本题求得子数组&#xff0c;其实就是连续的序列。定义一个二维dp数组&#xff0c;dp[i][j]的含义为&#xff1a;以下标i为结尾的nums1和以下标j为结尾的nums2之间的公共最长子数组。 易得&#xff1a;递推公式为dp[i][j] dp[i-1][j-1] 1&#xff1b; 由此可以看出当…

电商项目part05 微服务网关整合OAuth2.0授权中心

微服务网关整合 OAuth2.0 思路分析 网关整合 OAuth2.0 有两种思路&#xff0c;一种是授权服务器生成令牌, 所有请求统一在网关层验证&#xff0c;判断权 限等操作&#xff1b;另一种是由各资源服务处理&#xff0c;网关只做请求转发。 比较常用的是第一种&#xff0c;把API网关…

从零做软件开发项目系列之四——数据库设计

前言 在对软件进行设计的过程中&#xff0c;数据库的设计是一项重要的内容&#xff0c;软件中主要的处理对象就是各类业务数据&#xff0c;通过对业务数据的处理&#xff0c;实现各种功能。我们经常说的&#xff0c;写程序&#xff0c;说到底就是增删改查&#xff0c;而增删改…

IDEA远程开发

IDEA远程开发 前期准备 IDEA的远程开发是在本地去操昨远程服务器上的代码&#xff0c;所以我们先需要准备一台服务器,在此我使用vmware虚拟出ubuntu-20.04.6的Server版本,以便后面演示。 Ubuntu的Java环境配置 JDK8 sudo apt install openjdk-8-jdkmaven sudo apt instal…

NAT的配置实验

一、实验目的 学习如何配置NAT 二、预备知识: Net Address Translation:通过将内部用户的地址转换为1个公用的外部地址&#xff0c;然后再与外部的用户进行通信&#xff0c;从而既节省了IPv4地址&#xff0c;又实现了对内部用户的安全保护 三、实验过程&#xff1a; …

unity动画融合

1、抛砖引玉 在大型复杂的场景中&#xff0c;一定遇到过手在鼓掌&#xff0c;头在摇头&#xff0c;腿又是其他动作的要求&#xff0c;但是这些东西又不能做一起&#xff0c;因为有时候要把某个动画单独使用&#xff0c;这时候就用到了动画融合&#xff0c;利用动画状态机分层机…

taro react/vue h5 中的上传input onchange 值得区别

<inputclassNamebase-input-file-h5typefileacceptimage/*capturecameraonChange{onChangeInput} />1、taro3react 2、taro3vue3

Android12之ABuffer数据处理(三十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

【1267. 统计参与通信的服务器】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 这里有一幅服务器分布图&#xff0c;服务器的位置标识在 m * n 的整数矩阵网格 grid 中&#xff0c;1 表示单元格上有服务器&#xff0c;0 表示没有。 如果两台服务器位于同一行或者同一列&#xff…

docker可视化工具

安装Portainer 官方安装说明&#xff1a;https://www.portainer.io/installation/ [rootubuntu1804 ~]#docker pull portainer/portainer[rootubuntu1804 ~]#docker volume create portainer_data portainer_data [rootubuntu1804 ~]#docker run -d -p 8000:8000 -p 9000:90…