网站 html 文件被恶意更改 全部被定向到另外一个网站?

JavaScript 是浏览器的内置脚本语言。也就是说,浏览器内置了 JavaScript 引擎,并且提供各种接口,让 JavaScript 脚本可以控制浏览器的各种功能。一旦网页内嵌了 JavaScript 脚本,浏览器加载网页,就会去执行脚本,从而达到操作浏览器的目的,实现网页的各种动态效果。

本章开始介绍浏览器提供的各种 JavaScript 接口。首先,介绍 JavaScript 代码嵌入网页的方法。

1、代码嵌入网页的方法

网页中嵌入 JavaScript 代码,主要有三种方法。

//时,该页面的脚本设置了,新页面的脚本可以读到上一个网页设置的';

上面代码先打开一个新窗口,然后在该窗口弹出一个对话框,再将网址导向/,服务器在浏览器写入一个 Cookie。这个 Cookie 的所属域名为,生效路径为根路径/。如果 Cookie 的生效路径设为/forums,那么这个 Cookie 只有在访问/forums及其子路径时才有效。以后,浏览器访问某个路径之前,就会找出对该域名和路径有效,并且还没有到期的 Cookie,一起发送给服务器。

用户可以设置浏览器不接受 Cookie,也可以设置不向服务器发送 Cookie。设置的 Cookie,可以被/blog的时候,浏览器将向服务器发送两个同名的 Cookie。

上面代码的两个 Cookie 是同名的,匹配越精确的 Cookie 排在越前面。

Path属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。只要浏览器发现,Path属性是 HTTP 请求路径的开头一部分,就会在头信息里面带上这个 Cookie。比如,PATH属性是/,那么请求/docs路径也会包含该 Cookie。当然,前提是域名必须一致。



用户一旦被诱骗发送这个表单,银行网站就会收到带有正确 Cookie 的请求。为了防止这种攻击,表单一般都带有一个随机 token,告诉服务器这是真实请求。

浏览器加载上面代码时,就会向 Facebook 发出带有 Cookie 的请求,从而 Facebook 就会知道你是谁,访问了什么网站。

Cookie 的SameSite属性用来限制第三方 Cookie,从而减少安全风险。它可以设置三个值。

Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

这个规则过于严格,可能造成非常不好的用户体验。比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登陆状态。

Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。

导航到目标网址的 GET 请求,只包括三种情况:链接,预加载请求,GET 表单。详见下表。

设置了StrictLax以后,基本就杜绝了 CSRF 攻击。当然,前提是用户浏览器支持 SameSite 属性。

Chrome 计划将Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。

Cookie 的属性一旦设置完成,就没有办法读取这些属性的值。

删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期。

上面代码中,名为fontSize的 Cookie 的值为空,过期时间设为1970年1月1月零点,就等同于删除了这个 Cookie。

浏览器与服务器之间,采用 HTTP 协议通信。用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出 HTTP 请求。

withCredentials属性打开的话,跨域请求不仅会发送 Cookie,还会设置远程主机指定的 Cookie。反之也成立,如果withCredentials属性没有打开,那么跨域的 AJAX 请求即使明确要求浏览器设置 Cookie,浏览器也会忽略。

上面代码中,GET请求的参数,作为查询字符串附加在 URL 后面。

下面是发送 POST 请求的例子。

注意,所有 XMLHttpRequest 的监听事件,都必须在send()方法调用之前设定。

send方法的参数就是发送的数据。多种格式的数据,都可以作为它的参数

如果send()发送 DOM 对象,在发送之前,数据会先被串行化。如果发送二进制数据,最好是发送ArrayBufferViewBlob对象,这使得通过 Ajax 上传文件成为可能。

下面是发送表单数据的例子。FormData对象可以用于构造表单数据。

下面的例子是使用FormData对象加工表单数据,然后再发送。

上面代码使用setTimeout,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出。

这些做法的共同问题是,卸载的时间被硬生生拖长了,后面页面的加载被推迟了,用户体验不好。

为了解决这个问题,浏览器引入了/analytics';

浏览器安全的基石是“同源政策”()。很多开发者都知道这一点,但了解得不全面。

/dir/,端口是80(默认端口可以省略),它的同源情况如下。

  • 注意,A 和 B 两个网页都需要设置。

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

    iframe元素可以在当前网页之中,嵌入其他网页。每个iframe元素形成自己的窗口,即有自己的window对象。iframe窗口之中的脚本,可以获得父窗口和子窗口。但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM。

    比如,父窗口运行下面的命令,如果iframe窗口不是同源,就会报错。

    // 父窗口向子窗口发消息

    父窗口和子窗口都可以通过message事件,监听对方的消息。

    // 父窗口和子窗口都可以用下面的代码,
    

    message事件的参数是事件对象event,提供以下三个属性。

    • 上面代码中,子窗口将父窗口发来的消息,写入自己的 LocalStorage。

      父窗口发送消息的代码如下。

      注意,请求的脚本网址有一个callback参数(?callback=bar),用来告诉服务器,客户端的回调函数名称(bar)。

      第二步,服务器收到请求后,拼接一个字符串,将 JSON 数据放在函数名里面,作为字符串返回(bar({...}))。

      第三步,客户端会将服务器返回的字符串,作为代码解析,因为浏览器认为,这是<script>标签请求的脚本内容。这时,客户端只要定义了bar()函数,就能在该函数体内,拿到服务器返回的 JSON 数据。

      下面看一个实例。首先,网页动态插入<script>元素,由它向跨域网址发出请求。

      addScriptTag('发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于 JSONP 是必需的。

      服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

      上面代码中,HTTP 请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header

      浏览器发现,这是一个非简单请求,就自动发出一个“预检”请求,要求服务器确认可以这样请求。下面是这个“预检”请求的 HTTP 头信息。

      OPTIONS /cors HTTP/可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。
       

       
      如果服务器否定了“预检”请求,会返回一个正常的 HTTP 回应,但是没有任何 CORS 相关的头信息字段,或者明确表示请求不符合条件。

      这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

      服务器回应的其他 CORS 相关字段如下。

      该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次“预检”请求。

      如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段。

      该字段与简单请求时的含义相同。

      该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

      和共享 5MB 的存储空间。另外,与 Cookie 一样,它们也受同域限制。某个网页存入的数据,只有同域下的网页才能读取,如果跨域操作会报错。

      Storage 接口只有一个属性。

      • //),然后点击了倒退按钮,页面的 URL
       
      这些属性里面,只有origin属性是只读的,其他属性都可写。

      这个特性常常用于让网页自动滚动到新的锚点。

      直接改写location,相当于写入href属性。

      (3)/q=春节这个 URL 之中,汉字“春节”不是 URL 82,将每个字节前面加上百分号,就构成了 URL 编码。

      上面代码中,返回的 URL 实例的路径都是在第二个参数的基础上,切换到第一个参数得到的。最后一个例子里面,第一个参数是..,表示上层路径。

      上面代码中,fetch命令向服务器发送命令时,可以直接使用URLSearchParams实例。

      那么需要字符串的场合,会自动调用toString方法。

      上面代码中,写入数据需要新建一个事务。新建时必须指定表格名称和操作模式(“只读”或“读写”)。新建事务以后,通过' });

      上面代码中,put()方法自动更新了主键为1的记录。

      索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。

      假定新建表格的时候,对name字段建立了索引。

      现在,就可以从name找到对应的数据记录了。

      浏览器原生提供indexedDB对象,作为开发者的操作接口。

      上面代码表示,打开一个名为test、版本为1的数据库。如果该数据库不存在,则会新建该数据库。

      open()方法的第一个参数是数据库名称,格式为字符串,不可省略;第二个参数是数据库版本,是一个大于0的正整数(0将报错),如果该参数大于当前版本,会触发数据库升级。第二个参数可省略,如果数据库已存在,将打开当前版本的数据库;如果数据库不存在,将创建该版本的数据库,默认版本为1

      打开数据库是异步操作,通过各种事件通知客户端。下面是有可能触发的4种事件。

      • error:打开失败。
      • upgradeneeded:第一次打开该数据库,或者数据库版本发生变化。
      • blocked:上一次的数据库连接还未关闭。

      第一次打开数据库时,会先触发upgradeneeded事件,然后触发success事件。

      根据不同的需要,对上面4种事件监听函数。

      上面代码有两个地方需要注意。首先,open()方法返回的是一个对象(IDBOpenDBRequest),监听函数就定义在这个对象上面。其次,success事件发生后,从openRequest.result属性可以拿到已经打开的IndexedDB数据库对象。

      indexedDB.deleteDatabase()方法用于删除一个数据库,参数为数据库的名字。它会立刻返回一个IDBOpenDBRequest对象,然后对数据库执行异步删除。删除操作的结果会通过事件通知,IDBOpenDBRequest对象可以监听以下事件。

      调用deleteDatabase()方法以后,当前数据库的其他已经打开的连接都会接收到versionchange事件。

      注意,删除不存在的数据库并不会报错。

      indexedDB.cmp()方法比较两个值是否为 indexedDB 的相同的主键。它返回一个整数,表示比较的结果:0表示相同,1表示第一个主键大于第二个主键,-1表示第一个主键小于第二个主键。

      注意,这个方法不能用来比较任意的 JavaScript 值。如果参数是布尔值或对象,它会报错。

      这个对象的所有操作都是异步操作,要通过readyState属性判断是否完成,如果为pending就表示操作正在进行,如果为done就表示操作完成,可能成功也可能失败。

      操作完成以后,触发success事件或error事件,这时可以通过result属性和error属性拿到操作结果。如果在pending阶段,就去读取这两个属性,是会报错的。

      • IDBRequest.result:返回请求的结果。如果请求失败、结果不可用,读取该属性会报错。

      打开数据成功以后,可以从IDBOpenDBRequest对象的result属性上面,拿到一个IDBDatabase对象,它表示连接的数据库。后面对数据库的操作,都通过这个对象完成。

      • IDBDatabase.version:整数,数据库版本。数据库第一次创建时,该属性为空字符串。

      下面是objectStoreNames属性的例子。该属性返回一个 DOMStringList 对象,包含了当前数据库所有对象仓库的名称(即表名),可以使用 DOMStringList 对象的contains方法,检查数据库是否包含某个对象仓库。

      上面代码先判断某个对象仓库是否存在,如果不存在就创建该对象仓库。

      • IDBDatabase.close():关闭数据库连接,实际会等所有事务完成后再关闭。

      上面代码创建了一个名为items的对象仓库,如果该对象仓库已经存在,就会抛出一个错误。为了避免出错,需要用到下文的objectStoreNames属性,检查已有哪些对象仓库。

      createObjectStore()方法还可以接受第二个对象参数,用来设置对象仓库的属性。

      上面代码中,keyPath属性表示主键(由于主键的值不能重复,所以上例存入之前,必须保证数据的email属性值都是不一样的),默认值为nullautoIncrement属性表示,是否使用自动递增的整数作为主键(第一个数据记录为1,第二个数据记录为2,以此类推),默认为false。一般来说,keyPathautoIncrement属性只要使用一个就够了,如果两个同时使用,表示主键为递增的整数,且对象不得缺少keyPath指定的属性。

      下面是transaction()方法的例子,该方法用于创建一个数据库事务,返回一个 IDBTransaction 对象。向数据库添加数据之前,必须先创建数据库事务。

      transaction()方法接受两个参数:第一个参数是一个数组,里面是所涉及的对象仓库,通常是只有一个;第二个参数是一个表示操作类型的字符串。目前,操作类型只有两种:readonly(只读)和readwrite(读写)。添加数据使用readwrite,读取数据使用readonly。第二个参数是可选的,省略时默认为readonly模式。

      IDBObjectStore.add()用于向对象仓库添加数据,返回一个 IDBRequest 对象。该方法只用于添加数据,如果主键相同会报错,因此更新数据必须使用put()方法。

      该方法接受两个参数,第一个参数是键值,第二个参数是主键,该参数可选,如果省略默认为null

      创建事务以后,就可以获取对象仓库,然后使用add()方法往里面添加数据了。

      IDBObjectStore.put()方法用于更新某个主键对应的数据记录,如果对应的键值不存在,则插入一条新的记录。该方法返回一个 IDBRequest 对象。

      该方法接受两个参数,第一个参数为新数据,第二个参数为主键,该参数可选,且只在自动递增时才有必要提供,因为那时主键不包含在数据值里面。

      该方法的参数为主键的值。

      不带参数时,该方法返回当前对象仓库的所有记录数量。如果主键或 IDBKeyRange 对象作为参数,则返回对应的记录数量。

      该方法的参数可以是主键值或 IDBKeyRange 对象。

      // 指定获取记录的数量
      // 获取所有记录的主键
      // 获取所有符合条件的主键
      // 指定获取主键的数量
      

      有了索引以后,就可以针对索引所在的属性读取数据。

      上面代码打开对象仓库以后,先用index()方法指定获取name属性的索引,然后用get()方法读取某个name属性(foo)对应的数据。如果name属性不是对应唯一值,这时get()方法有可能取回多个数据对象。另外,get()是异步方法,读取成功以后,只能在success事件的监听函数中处理数据。

      该方法可以接受三个参数。

第三个参数可以配置以下属性。

  • unique:如果设为true,将不允许重复的值
  • multiEntry:如果设为true,对于有多个值的主键数组,每个值将在索引里面新建一个条目,否则主键数组对应一个条目。

假定对象仓库中的数据记录都是如下的person类型。

可以指定这个对象的某个属性来建立索引。

上面代码告诉索引对象,name属性不是唯一值,email属性是唯一值。

指针对象可以用来遍历数据。该对象也是异步的,有自己的successerror事件,可以对它们指定监听函数。

监听函数接受一个事件对象作为参数,该对象的target.result属性指向当前数据记录。该记录的keyvalue分别返回主键和键值(即实际存入的数据)。continue()方法将光标移到下一个数据对象,如果当前数据对象已经是最后一个数据了,则光标指向null

对象。如果指定该参数,将只处理包含指定主键的记录;如果省略,将处理所有的记录。该方法还可以接受第二个参数,表示遍历方向,默认值为next,其他可能的值为prevnextuniqueprevunique。后两个值表示如果遇到重复值,会自动跳过。

IDBTransaction 对象用来异步操作数据库事务,所有的读写操作都要通过这个对象进行。

事务的执行顺序是按照创建的顺序,而不是发出请求的顺序。

上面代码中,key对应的键值最终是2,而不是1。因为事务trans1先于trans2创建,所以首先执行。

注意,事务有可能失败,只有监听到事务的complete事件,才能保证事务操作成功。

  • IDBTransaction.error:返回当前事务的错误。如果事务没有结束,或者事务成功结束,或者被手动终止,该方法返回null

IDBIndex 对象代表数据库的索引,通过这个对象可以获取数据库里面的记录。数据记录的主键默认就是带有索引,IDBIndex 对象主要用于通过除主键以外的其他键,建立索引获取对象。

IDBIndex 是持久性的键值对存储。只要插入、更新或删除数据记录,引用的对象库中的记录,索引就会自动更新。

  • IDBIndex.multiEntry:布尔值,针对keyPath为数组的情况,如果设为true,创建数组时,每个数组成员都会有一个条目,否则每个数组都只有一个条目。
  • IDBIndex.unique:布尔值,表示创建索引时是否允许相同的主键。

IDBIndex 对象有以下方法,它们都是异步的,立即返回的都是一个 IDBRequest 对象。

  • IDBIndex.count():用来获取记录的数量。它可以接受主键或 IDBKeyRange 对象作为参数,这时只返回符合主键的记录数量,否则返回所有记录的数量。
  • IDBIndex.getAll():用来获取所有的数据记录。它可以接受两个参数,都是可选的,第一个参数用来指定主键,第二个参数用来指定返回记录的数量。如果省略这两个参数,则返回所有记录。由于获取成功时,浏览器必须生成所有对象,所以对性能有影响。如果数据集比较大,建议使用 IDBCursor 对象。

  • IDBCursor.direction:字符串,表示指针遍历的方向。共有四个可能的值:next(从头开始向后遍历)、nextunique(从头开始向后遍历,重复的值只遍历一次)、prev(从尾部开始向前遍历)、prevunique(从尾部开始向前遍历,重复的值只遍历一次)。该属性通过IDBObjectStore.openCursor()方法的第二个参数指定,一旦指定就不能改变了。
  • IDBCursor.continue():指针向前移动一个位置。它可以接受一个主键作为参数,这时会跳转到这个主键。
  • IDBCursor.delete():用来删除当前位置的记录,返回一个 IDBRequest 对象。该方法不会改变指针的位置。
  • IDBCursor.update():用来更新当前位置的记录,返回一个 IDBRequest 对象。它的参数是要写入数据库的新的值。

IDBKeyRange 对象代表数据仓库(object store)里面的一组主键。根据这组主键,可以获取数据仓库或索引里面的一组记录。

IDBKeyRange 可以只包含一个值,也可以指定上限和下限。它有四个静态方法,用来指定主键的范围。

与之对应,IDBKeyRange 对象有四个只读属性。

  • IDBKeyRange.lowerOpen:布尔值,表示下限是否为开区间(即下限是否排除在范围之外)
  • IDBKeyRange.upperOpen:布尔值,表示上限是否为开区间(即上限是否排除在范围之外)

IDBKeyRange 有一个实例方法includes(key),返回一个布尔值,表示某个主键是否包含在当前这个主键组之内。

JavaScript 语言采用的是单线程模型,也就是说,所有任务只能在一个线程上完成,一次只能做一件事。前面的任务没做完,后面的任务只能等着。随着电脑计算能力的增强,尤其是多核 CPU 的出现,单线程带来很大的不便,无法充分发挥计算机的计算能力。

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务可以交由 Worker 线程执行,主线程(通常负责 UI 交互)能够保持流畅,不会被阻塞或拖慢。

Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。

Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用documentwindowparent这些对象。但是,Worker 线程可以使用navigator对象和location对象。

的全局对象存在console接口,只定义了Navigator接口和Location接口。不过,浏览器实际上支持 Worker 线程使用console.log,保险的做法还是不使用这个方法。

Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。

Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。

主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。

Worker()构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。

worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。

接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。

上面代码中,事件对象的data属性可以获取 Worker 发来的数据。

Worker 完成任务以后,主线程就可以把它关掉。

Worker 线程内部需要有一个监听函数,监听message事件。

上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法。

除了使用self.addEventListener()指定监听函数,也可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息。

根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。

该方法可以同时加载多个脚本。

主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件。

使用完毕,为了节省系统资源,必须关闭 Worker。

前面说过,主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。

主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。

但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

如果要直接转移数据的控制权,就要使用下面的写法。

通常情况下,Worker 载入的是一个单独的 JavaScript 脚本文件,但是也可以载入与主线程在同一个网页的代码。

上面是一段嵌入网页的脚本,注意必须指定``标签的type属性是一个浏览器不认识的值,上例是app/worker

然后,读取这一段嵌入页面的脚本,用 Worker 来处理。

上面代码中,先将嵌入网页的脚本代码,转成一个二进制对象,然后为这个二进制对象生成 URL,再让 Worker 加载这个 URL。这样就做到了,主线程和 Worker 的代码都在同一个网页上面。

5、实例:Worker 线程完成轮询

有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在 Worker 里面。

上面代码中,Worker 每秒钟轮询一次数据,然后跟缓存做比较。如果不一致,就说明服务端有了新的变化,因此就要通知主线程。

Worker 线程内部还能再新建 Worker 线程(目前只有 Firefox 浏览器支持)。下面的例子是将一个计算密集的任务,分配到10个 Worker。

上面代码中,Worker 线程内部新建了10个 Worker 线程,并且依次向这10个 Worker 发送消息,告知了计算的起点和终点。计算任务脚本的代码如下。

浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。

Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。

Worker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。

Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。

Worker 线程有一些自己的全局属性和方法。

  • self.name: Worker 的名字。该属性只读,由构造函数指定。
  • self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。

        你电脑上的所有文档、照片、工作文件、隐私文件与及其它重要文件都已经被加密。要解密这些文件,请运行桌面上的<文件解密>工具;如果桌面上没有这个工具,请前往每一个分区的根目录下查找;如果仍然无法找到该工具,请继续阅读此帮助内容;

        只有严格按照稍后提示的步骤进行,才能解密你的文件;请不要使用杀毒软件或者其它任何工具尝试恢复文件,因为这将会破坏或删除被加密的文件,导致文件永远无法恢复!

        你首先要下载并安装《Tor浏览器》;请百度搜索"Tor浏览器中文版",找到下载地址,下载并安装;或者直接从官网 上下载安装; 如果你是第1次使用此浏览器,你可能还需要百度搜索"Tor浏览器使用"获取相关的使用教程;

        由于Tor网络已经被封锁,你可能还需要使用国外的VPN或者为Tor浏览器配置国外代理服务器;如果你并不懂得如何操作,请在网上搜索相关的资料或者寻求专业人员的帮助;

        在确认已经连接上Tor网络的前提下,在Tor浏览器中输入网址访问此网站: ,如果网站暂时无法打开,请稍后继续重试;

        如果解密工具已丢失,你可以从此网站上重新下载一个;运行解密工具的时候,请确保杀毒软件处于关闭状态;

        打开网站后,复制以下机器码输入并提交,然后根据网站的提示进行操作;如果成功,你将获得一个唯一的密钥,这个密钥将可以解密你所有的文件;

我要回帖

更多关于 网页被强制跳转怎么办 的文章

 

随机推荐