运行Google Search Console书签脚本时遭遇CORB跨域拦截错误求助
问题描述
运行书签脚本调用PHP脚本对接Google Search Console获取当前URL查询数据时,触发CORB错误:
Cross-Origin Read Blocking (CORB) blocked a cross-origin response.
请求地址:search-console-queries.php?url=https%3A%2F%2Fsomedomain.edu%2Fpayingforcollege%2Findex.php&callback=handleResponse
相关代码
书签脚本
javascript:(function(){var script = document.createElement('script');script.src = 'https://www.somedomain.edu/_resources/php/abstraction_layers/google/search-console-queries.php?url=' + encodeURIComponent(window.location.href) + '&callback=handleResponse';document.body.appendChild(script);window.handleResponse = function(data) { console.log(data); }})();
Search Console PHP脚本
<?php header('Content-Type: application/json'); // Explicitly set the content type to JSON header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: POST, GET, OPTIONS"); header("Access-Control-Allow-Headers: Authorization, Content-Type"); if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { // Send OK status for preflight, no further action needed http_response_code(200); exit; } $clientId = 'jkwekjwrjlwr-4u2928482498248.apps.googleusercontent.com'; $clientSecret = 'RANDO-M4298424-3813938938913'; $redirectUri = 'https://somedomain.edu/_resources/php/abstraction_layers/google/search-console-queries.php'; // Google's OAuth 2.0 endpoints $authUrl = 'https://accounts.google.com/o/oauth2/v2/auth'; $tokenUrl = 'https://oauth2.googleapis.com/token'; session_start(); function getAccessToken($clientId, $clientSecret, $redirectUri, $code) { global $tokenUrl; // Access global variable within function $tokenData = [ 'code' => $code, 'client_id' => $clientId, 'client_secret' => $clientSecret, 'redirect_uri' => $redirectUri, 'grant_type' => 'authorization_code', ]; $opts = [ 'http' => [ 'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded ", 'content' => http_build_query($tokenData) ] ]; $context = stream_context_create($opts); $response = file_get_contents($tokenUrl, false, $context); return json_decode($response, true)['access_token']; } // OAuth flow if (!isset($_GET['code']) && !isset($_SESSION['access_token'])) { $authParams = http_build_query([ 'response_type' => 'code', 'client_id' => $clientId, 'redirect_uri' => $redirectUri, 'scope' => 'https://www.googleapis.com/auth/webmasters.readonly', 'access_type' => 'offline' ]); header('Location: ' . $authUrl . '?' . $authParams); exit; } if (isset($_GET['code']) && !isset($_SESSION['access_token'])) { $_SESSION['access_token'] = getAccessToken($clientId, $clientSecret, $redirectUri, $_GET['code']); } if (isset($_SESSION['access_token'])) { $accessToken = $_SESSION['access_token']; // Validate the URL parameter to prevent injection attacks $url = filter_var($_GET['url'], FILTER_VALIDATE_URL); if ($url === false) { echo json_encode(['error' => 'Invalid URL']); exit; } // Calculate dates $startDate = date('Y-m-d', strtotime("-30 days")); $endDate = date('Y-m-d'); // Today's date // Search Console API request $apiUrl = 'https://www.googleapis.com/webmasters/v3/sites/' . urlencode($url) . '/searchAnalytics/query'; $requestBody = json_encode([ 'startDate' => $startDate, 'endDate' => $endDate, 'dimensions' => ['query'], 'rowLimit' => 1000 ]); $opts = [ 'http' => [ 'method' => 'POST', 'header' => "Authorization: Bearer $accessToken " . "Content-Type: application/json ", 'content' => $requestBody ] ]; $context = stream_context_create($opts); $response = file_get_contents($apiUrl, false, $context); // Output the response echo $response; } ?>
问题根源及解决办法
你使用的是JSONP方式(通过<script>标签加载并指定callback参数),但PHP脚本返回纯JSON而非JSONP格式,浏览器会拦截跨域脚本返回的非JavaScript类型内容,触发CORB。
修复步骤
修改PHP脚本支持JSONP格式
检查URL中的callback参数,存在时将JSON数据包裹在回调函数中返回,同时调整响应头:
将原脚本最后输出echo $response;的部分替换为:if (isset($_GET['callback']) && preg_match('/^[a-zA-Z0-9_]+$/', $_GET['callback'])) { header('Content-Type: application/javascript'); echo $_GET['callback'] . '(' . $response . ');'; } else { header('Content-Type: application/json'); echo $response; }注意:OAuth跳转流程触发前不能输出任何内容,避免破坏响应格式。
调整会话Cookie参数
书签脚本运行在当前页面域名,PHP脚本在somedomain.edu,会话依赖Cookie,需确保跨域场景下会话有效:
在session_start()前添加:session_set_cookie_params([ 'sameSite' => 'None', 'secure' => true, 'httponly' => true ]);清理冗余CORS配置
因为用的是JSONP,CORS头并非必须,如果保留需确保Content-Type与返回内容匹配(JSONP对应application/javascript,JSON对应application/json)。
内容的提问来源于stack exchange,提问作者Web Marketing

