js逆向之浏览器控制台
首先介绍一下浏览器控制台的使用,以开发者使用最多的chrome为例。Windows操作系统下的F12键可以打开控制台,mac操作系统下用Fn+F12键打开。我们选择平时使用较多的模块进行介绍
2.1 Network
Network是Js调试的重点,面板上由控制器、过滤器、数据流概览、请求列表、数据统计这五部分组成。

- 控制器:Presserve Log是保留请求日志的作用,在跳转页面的时候勾选上可以看到跳转前的请求。Disable cache是禁止缓存的作用,Offline是离线模拟。
- 过滤器:根据规则过滤器请求列表的内容,可以选择XHR,JS,CSS,WS等。
- 数据流概览:显示HTTP请求、响应的时间轴。
- 请求列表:默认是按时间排序,可以看到浏览器所有的请求,主要用于网络请求的查看和分析,可以查看请求头、响应状态和内容、Form表单等。
- 数据统计:请求总数、总数据量、总花费时间等。
浏览器控制台Network下各项属性的含义
作用:
- 可以查看调取接口是否正确,后台返回的数据;
- 查看请求状态、请求类型、请求地址
2.1.1 Network-Headers
首先打开控制台,找到Network. 刷新页面可以看到Name
Name对应的是资源的名称及路径, Status Code 是请求服务器返回的状态码,一般情况下当状态码为200时,则表示接口匹配成功。点击任一文件名,右侧会出现Header选项。

Network-Header-General
- Request URL: 资源请求的url
- Request Method: 请求方法(HTTP方法)
- Status Code: 状态码
- 200(状态码) OK
- 301 - 资源(网页等)被永久转移到其它URL
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误(后台问题)
- Remote Address: 远程地址;
- Referrer Policy: 控制请求头中 refrrer 的内容
包含值的情况:- “”, 空串默认按照浏览器的机制设置referrer的内容,默认情况下是和no-referrer-when-downgrade设置得一样
- “no-referrer”, 不显示 referrer的任何信息在请求头中
- “no-referrer-when-downgrade”, 默认值。当从https网站跳转到http网站或者请求其资源时(安全降级HTTPS→HTTP),不显示 referrer的信息,其他情况(安全同级HTTPS→HTTPS,或者HTTP→HTTP)则在 referrer中显示完整的源网站的URL信息
- “same-origin”, 表示浏览器只会显示 referrer信息给同源网站,并且是完整的URL信息。所谓同源网站,是协议、域名、端口都相同的网站
- “origin”, 表示浏览器在 referrer字段中只显示源网站的源地址(即协议、域名、端口),而不包括完整的路径
- “strict-origin”, 该策略更为安全些,和 origin策略相似,只是不允许 referrer信息显示在从https网站到http网站的请求中(安全降级)
- “origin-when-cross-origin”, 当发请求给同源网站时,浏览器会在 referrer中显示完整的URL信息,发个非同源网站时,则只显示源地址(协议、域名、端口)
- “strict-origin-when-cross-origin”, 和 origin-when-cross-origin相似,只是不允许 referrer信息显示在从https网站到http网站的请求中(安全降级)
- “unsafe-url” 浏览器总是会将完整的URL信息显示在 referrer字段中,无论请求发给任何网站
- 补充: 什么是referrer?
- 当一个用户点击页面中的一个链接,然后跳转到目标页面时,本变页面会收到一个信息,即用户是从哪个源链接跳转过来的。
- 也就是说当你发起一个HTTP请求,请求头中的 referrer 字段就说明了你是从哪个页面发起该请求的;
Network-Header-Response Headers
- Access-Control-Allow-Origin: 请求头中允许设置的请求方法
- Connection: 连接方式
- content-length: 响应数据的数据长度,单位是byte
- content-type: 客户端发送的类型及采用的编码方式
- Date: 客户端请求服务端的时间
- Vary: 用来指示缓存代理(例如squid)根据什么条件去缓存一个请求
- Last-Modified: 服务端对该资源最后修改的时间
- Server: 服务端的web服务端名
- Content-Encoding: gzip 压缩编码类型
- Transfer-Encoding:chunked: 分块传递数据到客户端
Network-Header-Request Headers
- Accept: 客户端能接收的资源类型
- Accept-Encoding: 客户端能接收的压缩数据的类型
- Accept-Language: 客户端接收的语言类型
- Cache-Control: no-cache 服务端禁止客户端缓存页面数据
- Connection: keep-alive 维护客户端和服务端的连接关系
- Cookie:客户端暂存服务端的信息
- Host: 连接的目标主机和端口号
- Pragma: no-cache 服务端禁止客户端缓存页面数据
- Referer: 来于哪里(即从哪个页面跳转过来的)
- User-Agent: 客户端版本号的名字
2.2 Sources
Sources按列分为三列,从左至右分别是文件列表区、当前文件区、断点调试区。

文件列表区中有Page、Snippets、FileSytem等。Page可以看到当前所在的文件位置,在Snippets中单击New Snippets可以添加自定义的Js代码,FileSytem可以把本地的文件系统导入到chrome中。
当前文件区是需要重点操作的区域,单击下方的{}来格式化代码,就能看到美观的Js代码,然后可以根据指定行数进行断点调试。
断点调试区也非常重要,每个操作点都需要了解是什么作用。最上方的功能区分别是暂停、跳过、进入、跳出、步骤进入、禁用断点、异常断点。
Watch:变量监听,对加入监听列表的变量进行监听。
Call Stack:断点的调用堆栈列表,完整地显示了导致代码被暂停的执行路径。
Scope:当前断点所在函数执行的作用域内容。
Breakpoints:断点列表,将每个断点所在文件/行数/改成简略内容进行展示。
DOM Breakpoints:DOM断点列表。
XHR/fetch Breakpoints:对达到满足过滤条件的请求进行断点拦截。
Event Listener Breakpoints:打开可监听的事件监听列表,可以在监听事件并且触发该事件时进入断点,调试器会停留在触发事件代码行。
2.3 Application
Application是应用管理部分,主要记录网站加载的所有资源信息。包括存储数据(Local Storage、Session Storage、InDexedDB、Web SQL、Cookies)、缓存数据、字体、图片、脚本、样式表等。Local Storage(本地存储)和 Session Storage中可以查看和管理其存储的键值对。这里使用最多的是对Cookies的管理了,有时候调试需要清除Cookies,可以在Application的Cookies位置单击鼠标右键,选择Clear进行清除,或者根据Cookies中指定的Name和Value来进行清除,便于进一步调试。

注意:我们辨别Cookie来源时,可以看httpOnly这一栏,有√的是来自于服务端,没有√的则是本地生成的。
2.4 Console
谷歌控制台中的Console区域用于审查DOM元素、调试JavaScript代码、查看HTML解析,一般是通过Console.log()来输出调试信息。在Console中也可以输出window、document、location等关键字查看浏览器环境,如果对某函数使用了断点,也可以在Console中调用该函数。
如果你平时只是用console.log()来输出一些变量的值,那你肯定还没有用过console的强大的功能。下面带你用console玩玩花式调试。
来看下主要的调试函数及用法:
console.log(), console.error(), console.warn(), console.info()
最基本也是最常用的用法了,分别表示输出普通信息、错误信息、警示信息和提示性信息,且error和warn方法有特定的图标和颜色标识。
console.assert(expression, message)
- 参数:
- expression: 条件语句,语句会被解析成 Boolean,且为 false 的时候会触发message语句输出
- message: 输出语句,可以是任意类型
- 该函数会在 expression 为 false 的时候,在控制台输出一段语句,输出的内容就是传入的第二个参数 message 的内容。当我们在只需要在特定的情况下才输出语句的时候,可以使用 console.assert
- 示例如下:
function greaterThan(a,b) { console.assert(a > b, {"message":"a is not greater than b","a":a,"b":b}); } greaterThan(5,6);
console.count(label)
- 参数:
- label: 计算数量的标识符
- 该函数用于计算并输出特定标识符为参数的console.count函数被调用的次数。下面的例子更能直观的了解:
function login(name) { console.count(name + ' logged in'); }
console.dir(object)
- 参数:
- object:被输出扎实的对象
- 该函数用于打印出对象的详细的属性、函数及表达式等信息。如果该对象已经被记录为一个HTML元素,则该HTML元素的DOM表达式的属性会被像下面这样打印出来:
console.dir(document.body);
console.dirxml(object)
- 该函数将打印输出XML元素及其子孙后代元素,且对HTML和XML元素调用 console.dirxml() 和 调用 console.log() 是等价的
console.group([label]), console.groupEnd([label])
- 参数:
- label: group分组的标识符
- 在控制台创建一个新的分组,随后输出到控制台上的内容都会自动添加一个缩进,表示该内容属于当前分组,知道调用 console.groupEnd() 之后,当前分组结束。
- 举个例子:
console.log("This is the outer level"); console.group(); console.log("Level 2"); console.group(); console.log("Level 3"); console.warn("More of level 3"); console.groupEnd(); console.log("Back to level 2"); console.groupEnd(); console.log("Back to the outer level");
console.groupCollapsed(label)
- 该函数同console.group(),唯一的区别是该函数的输出默认不展开分组,而console.group()是默认展开分组。
console.time([label]), console.timeEnd([label])
- label: 用于标记计时器的名称,不填的话,默认为 default
- console.time() 会开始一个计时器,并当执行到 console.timeEnd() 函数时(需要两个函数的lable参数相同),结束计时器,并将计时器的总时间输出到控制台上。
- 再举几个例子:
console.time(); var arr = new Array(10000); for (var i = 0; i < arr.length; i++) { arr[i] = new Object(); } console.timeEnd(); // default: 3.696044921875ms- 对 console.time(label) 设置一个自定义的 label 字段,并使用console.timeEnd(label) 设置相同的 label 字段来结束计时器。
console.time('total'); var arr = new Array(10000); for (var i = 0; i < arr.length; i++) { arr[i] = new Object(); } console.timeEnd('total'); // total: 3.696044921875ms- 设置多个 label 属性,开启多个计时器同步计时。
console.time('total'); console.time('init arr'); var arr = new Array(10000); console.timeEnd('init arr'); for (var i = 0; i < arr.length; i++) { arr[i] = new Object(); } console.timeEnd('total'); // init arr: 0.0546875ms // total: 2.5419921875ms
console.trace(object)
- 该函数将在控制台打印出从 console.trace() 被调用的位置开始的堆栈信息。