有关于chrome跨域访问的问题(CORS)
最近在解决一个跨域访问的问题时。浏览器总是报错,错误信息如下:
Access to XMLHttpRequest at ‘网址B’ from origin ‘网址A’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
这里有一些很不错的文章是关于解释CORS如何工作的
https://www.html5rocks.com/en/tutorials/cors/
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
1.该错误信息来源
network中cors中会做访问检查,这里的错误信息是缺少allow_origin_header导致的。
base::Optional<CorsErrorStatus> CheckAccessInternal(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
const base::Optional<std::string>& allow_credentials_header,
mojom::CredentialsMode credentials_mode,
const url::Origin& origin) {
...
else if (!allow_origin_header) {
return CorsErrorStatus(mojom::CorsError::kMissingAllowOriginHeader);
}
...
}
2.尝试解决方法
1.https://peter.sh/experiments/chromium-command-line-switches/
在该网址中有一个**–disable-web-security**的开关,官方意思Don’t enforce the same-origin policy. (Used by people testing their sites.)
在启动浏览器时加入该参数,未能解决问题,怀疑是此开关未起作用。
2.在chromium源码web_preferences.h中定义了一些首选项
其中包含web_security_enabled; 看名字感觉与disable-web-security有关系
经测试将web_security_enabled置为false,即可跨域访问
3.调查web_security_enabled这个首选项是如何起作用的
在Browser进程的RenderViewHostImpl中
持有成员
std::unique_ptr<WebPreferences> web_preferences_;
在Render进程的RenderViewImpl中
持有成员
WebPreferences webkit_preferences_;
RenderViewHostImpl中有个ComputeWebPreferences会去获取当前进程中的command_line
const WebPreferences RenderViewHostImpl::ComputeWebPreferences() {
TRACE_EVENT0("browser", "RenderViewHostImpl::GetWebkitPrefs");
WebPreferences prefs;
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
SetSlowWebPreferences(command_line, &prefs);
//在command_line中检查是否含有开关kDisableWebSecurity
//如果command_line中含有该开关就会把web_security_enabled置为false
//至于为什么加了该command_line却不起作用,这个还需调查一下
prefs.web_security_enabled =
!command_line.HasSwitch(switches::kDisableWebSecurity);
...
return prefs;
}
void RenderViewHostImpl::OnWebkitPreferencesChanged() {
...
UpdateWebkitPreferences(ComputeWebPreferences());
...
}
void RenderViewHostImpl::UpdateWebkitPreferences(const WebPreferences& prefs) {
web_preferences_.reset(new WebPreferences(prefs));
Send(new ViewMsg_UpdateWebPreferences(GetRoutingID(), prefs));
}
在更新了web_preferences_之后会发一个IPC消息到render进程
IPC定义在src/content/common/view_messages.h
// This passes a set of webkit preferences down to the renderer.
IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences,
content::WebPreferences)
对应在render进程中的RenderViewImpl中会接受并处理该IPC消息
IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) {
webkit_preferences_ = prefs;
ApplyWebPreferences(webkit_preferences_, webview());
}
void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
WebView* web_view) {
WebSettings* settings = web_view->GetSettings();
settings->SetWebSecurityEnabled(prefs.web_security_enabled);
...
}
void WebSettingsImpl::SetWebSecurityEnabled(bool enabled) {
//WebSettingsImpl持有Settings* settings_;这个Setting是CORE_EXPORT的
settings_->SetWebSecurityEnabled(enabled);
}
Settings中大部分参数以及Get和Set方法都以宏定义的方式放于一个巨集中settings_macros.h
void Settings::SetWebSecurityEnabled(bool web_security_enabled) {
if (web_security_enabled_ == web_security_enabled)
return;
web_security_enabled_ = web_security_enabled;
}
bool GetWebSecurityEnabled() const { return web_security_enabled_; }
在这里还含有一个方法
bool GetAllowUniversalAccessFromFileURLs() const { return allow_universal_access_from_file_urls_; }
在src/third_party/blink/renderer/core/dom/document.cc
void InitializeOrigin(const DocumentInit& initializer) {
...
if (initializer.HasSecurityContext()) {
if (Settings* settings = initializer.GetSettings()) {
if (!settings->GetWebSecurityEnabled()) {
// Web security is turned off. We should let this document access
// every other document. This is used primary by testing harnesses for
// web sites.
//这里是把SecurityOrigin持有的通用访问权限universal_access_ 置为true默认是false
security_origin_->GrantUniversalAccess();
} else if (security_origin_->IsLocal()) {
if (settings->GetAllowUniversalAccessFromFileURLs()) {
// Some clients want local URLs to have universal access, but that
// setting is dangerous for other clients.
security_origin_->GrantUniversalAccess();
} else if (!settings->GetAllowFileAccessFromFileURLs()) {
// Some clients do not want local URLs to have access to other local
// URLs.
security_origin_->BlockLocalAccessFromLocalOrigin();
}
}
}
}
...
}
(未完)