Products
GG网络技术分享 2025-03-18 16:08 0
对浏览器加载资源有很多不确定性,例如:
通过源码可以找到答案。此次源码解读基于Chromium 64(10月28日更新的源码)。
下面通过加载资源的步骤,依次说明。
通过以下命令打开Chromium,同时打开一个网页:
chromium --renderer-startup-dialog https://www.baidu.com
Chrome会在DocumentLoader.cpp里面通过以下代码去加载:
main_resource_=RawResource::FetchMainResource(fetch_params,Fetcher(),substitute_data_);
页面资源属于MainRescouce,Chrome把Rescource归为以下几种:
enumType:uint8_t{kMainResource,kImage,kCSSStyleSheet,kScript,kFont,kRaw,kSVGDocument,kXSLStyleSheet,kLinkPrefetch,kTextTrack,kImportResource,kMedia,// Audio or video file requested by a HTML5 media elementkManifest,kMock// Only for testing};
除了常见的image/css/js/font之外,我们发现还有像textTrack的资源,这个是什么东西呢?这个是video的字幕,使用webvtt格式:
<videocontrolsposter="/images/sample.gif"><sourcesrc="sample.mp4"type="video/mp4"><trackkind="captions"src="sampleCaptions.vtt"srclang="en">video>
还有动态请求ajax属于Raw类型。因为ajax可以请求多种资源。
MainResource包括location即导航输入地址得到的页面、使用frame/iframe嵌套的、通过超链接点击的页面以及表单提交这几种。
接着交给稍底层的ResourceFecher去加载,所有资源都是通过它加载:
fetcher->RequestResource(params,RawResourceFactory(Resource::kMainResource),substitute_data)
在这个里面会先对请求做预处理。
每发个请求会生成一个ResourceRequest对象,这个对象包含了http请求的所有信息:
包括url、http header、http body等,还有请求的优先级信息等:
然后会根据页面的加载策略对这个请求做一些预处理,如下代码:
PrepareRequestResultresult=PrepareRequest(params,factory,substitute_data,identifier,blocked_reason);if(result==kAbort)returnnullptr;if(result==kBlock)returnResourceForBlockedRequest(params,factory,blocked_reason);
prepareRequest会做两件事情,一件是检查请求是否合法,第二件是把请求做些修改。如果检查合法性返回kAbort或者kBlock,说明资源被废弃了或者被阻止了,就不去加载了。
被block的原因可能有以下几种:
enumclassResourceRequestBlockedReason{kCSP,// CSP内容安全策略检查kMixedContent,// mixed contentkOrigin,// secure originkInspector,// devtools的检查器kSubresourceFilter,kOther,kNone};
源码里面会在这个函数做合法性检查:
blocked_reason=Context().CanRequest(/*参数省略*/);if(blocked_reason!=ResourceRequestBlockedReason::kNone){returnkBlock;}
CanRequest函数会相应地检查以下内容:
CSP是减少XSS攻击一个策略。如果我们只允许加载自己域的图片的话,可以加上下面这个meta标签:
<metahttp-equiv="Content-Security-Policy"content="img-src "self";">
或者是后端设置这个http响应头。
self表示本域,如果加载其它域的图片浏览器将会报错:
所以这个可以防止一些XSS注入的跨域请求。
源码里面会检查该请求是否符合CSP的设定要求:
constContentSecurityPolicy*csp=GetContentSecurityPolicy();if(csp
Demand feedback