由于内容安全政策,谷歌地图 API 脚本确实会加载

问题描述 投票:0回答:4

我正在制作一个谷歌浏览器扩展,我想在其中使用谷歌地图。问题是,当我运行我的脚本时,它给了我这个错误

Refused to load script from 'https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXXX&sensor=false' because of Content-Security-Policy.

这是我的清单文件

{
  "name": "Name",
  "version": "1.0",
  "manifest_version": 2,
  "background": { 
    "scripts": [
      "js/script.js"
    ] 
  },
  "description": "Desc",
  "browser_action": {
    "default_icon": "images/icon.png",
    "default_title": "Title",
    "default_popup": "html/popup.html"
  },
  "permissions": [ 
    "http://*/",
    "http://*.google.com/",
    "http://localhost/*"
  ],
  "content_security_policy": "script-src 'self' http://google.com; object-src 'self'"

}

我正在添加这样的脚本

<script src="../js/libs/jquery.js"></script>
  <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXX&sensor=false"></script>
  <script src="../js/plugins/easing.js"></script>
  <script src="../js/script.js"></script>

为什么我一次又一次地收到该错误?请帮忙...

更新一个

我将这两个权限添加到清单文件中,但仍然不起作用

"https://maps.google.com/*",
"https://maps.googleapis.com/*",

更新两个

我也使用了这种 content_security_policy

"content_security_policy": "default-src 'none'; style-src 'self'; script-src 'self'; connect-src https://maps.googleapis.com; img-src https://maps.google.com"

但是上面对我也不起作用

javascript jquery google-maps google-chrome-extension content-security-policy
4个回答
32
投票

我认为这里的问题是您没有正确设置Google Maps URL的内容安全策略。您应该将清单文件中的“content_security_policy”更改为如下所示:

"content_security_policy": "script-src 'self' https://maps.googleapis.com https://maps.gstatic.com; object-src 'self'"

这仅仅意味着您允许从自身/当前页面以及“https://maps.googleapis.com”运行脚本。

试试这个,看看是否有帮助。


2
投票

我遇到了同样的问题,通过将 API URL 从 http 替换为 https 版本解决了。

在 HTML 中 来自:

<script type='text/javascript' src='http://maps.google.com/maps/api/js?v=3.3&sensor=false'></script>

致:

<script type='text/javascript' src='https://maps-api-ssl.google.com/maps/api/js?v=3.3&sensor=false'></script>

然后将https://maps-api-ssl.google.com添加到manifest.json中的CPS

我不知道您是否还需要此信息。但我在谷歌上搜索并花了一些时间但找不到直接答案,所以我写在这里希望它是否对任何人有帮助。


0
投票

内容安全策略可确保您免受 XSS 攻击。但这意味着您需要明确地将外部资源列入白名单。您可以通过提供额外的 HTTP 标头或通过 <meta> 标签来实现,例如:


<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: ws: ; style-src 'self' https: *.googleapis.com; script-src 'self' https: *.googleapis.com; media-src 'none'; font-src *; connect-src *; img-src 'self' data: content: https: *.googleapis.com;">



0
投票
安装包以支持 Google Places API 类型:
npm 我@types/google.maps -D

    向您的manifest.json 文件添加“脚本”权限。
  1. 为了避免加载大多数与 google place api 一起使用的库使用的 .js 文件 - 我们可以在构建扩展版本之前加载它,这将允许您绕过 chrome 的远程代码策略问题 对于我来说,这段代码足以实现这些目的:
预构建.ts:

import * as fs from 'fs'; import config from './config/config.json'; const apiKey = config.GOOGLE_MAPS_API_KEY; (async () => { const libraries = ['places'].join(','); const response = await fetch(`https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=${libraries}`); const data = await response.text(); fs.writeFileSync('./src/inject/googlePlaces.js', data); })();


为了维护这个文件的最新版本,我还在package.json中添加了一个运行脚本:
package.json

{ "name": "example", "version": "0.0.1", "description": "", "keywords": [], "author": "[email protected]", "scripts": { "start": "npm run pre-build && webpack --mode=development --watch --progress", "build": "npm run pre-build && webpack --mode=production", "pre-build": "ts-node pre-build.ts" }, "dependencies": { "use-debounce": "^3.4.3", "react": "^18.3.1", ... }, "devDependencies": { "@types/chrome": "^0.0.276", "@types/google.maps": "^3.58.1", ... } }


由于我的扩展是基于 React 编写的,因此我创建了一个 React hook 来与 GooglePlacesAPI 交互:
使用GooglePlaces.ts:

import { useEffect } from 'react'; import { useDebouncedCallback } from 'use-debounce'; export type GooglePlacesAutocompleteHandle = { getSessionToken: () => google.maps.places.AutocompleteSessionToken | undefined; refreshSessionToken: () => void; }; export interface LatLng { lat: number; lng: number; } export interface AutocompletionRequest { bounds?: [LatLng, LatLng]; componentRestrictions?: { country: string | string[] }; location?: LatLng; offset?: number; radius?: number; types?: string[]; } export default interface GooglePlacesAutocompleteProps { autocompletionRequest?: AutocompletionRequest; debounce?: number; minLengthAutocomplete?: number; onLoadFailed?: (error: Error) => void; withSessionToken?: boolean; } export const useGooglePlacesAutocomplete = ({ autocompletionRequest = {}, debounce = 300, minLengthAutocomplete = 0, onLoadFailed = console.error, withSessionToken = false, }: GooglePlacesAutocompleteProps): ((value: string, cb: (options: google.maps.places.AutocompletePrediction[]) => void) => void) => { const [fetchSuggestions] = useDebouncedCallback(async (value: string, cb: (options: google.maps.places.AutocompletePrediction[]) => void) => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab?.id) return cb([]); const [res] = await chrome.scripting.executeScript({ target: { tabId: tab.id }, world: 'MAIN', func: async (value: string, minLengthAutocomplete: number, withSessionToken: boolean, autocompletionRequest: AutocompletionRequest): Promise<google.maps.places.AutocompletePrediction[]> => { if (!window.google) throw new Error('[react-google-places-autocomplete]: Google script not loaded'); if (!window.google.maps) throw new Error('[react-google-places-autocomplete]: Google maps script not loaded'); if (!window.google.maps.places) throw new Error('[react-google-places-autocomplete]: Google maps places script not loaded'); const PlacesService = new google.maps.places.AutocompleteService(); const SessionToken = new google.maps.places.AutocompleteSessionToken(); console.log('value', value); if (value.length < minLengthAutocomplete) return []; const autocompletionRequestBuilder = ( autocompletionRequest: AutocompletionRequest, input: string, sessionToken?: google.maps.places.AutocompleteSessionToken, ): google.maps.places.AutocompletionRequest => { const { bounds, location, componentRestrictions, offset, radius, types } = autocompletionRequest; const res: google.maps.places.AutocompletionRequest = { input, componentRestrictions, offset, radius, types, ...(sessionToken ? { sessionToken: SessionToken } : {}), ...(bounds ? { bounds: new google.maps.LatLngBounds(...bounds) } : {}), ...(location ? { location: new google.maps.LatLng(location) } : {}), }; return res; }; const waitPromise = <T>(promise: Promise<T>, timeout: number): Promise<T | Error> => { return Promise.race([promise, new Promise<Error>((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout))]); }; const data = PlacesService.getPlacePredictions(autocompletionRequestBuilder(autocompletionRequest, value, withSessionToken && SessionToken)); const res = await waitPromise(data, 5000); if (!(res instanceof Error)) return res.predictions; return []; }, args: [value, minLengthAutocomplete, withSessionToken, autocompletionRequest], }); if (res) { return cb(res.result); } }, debounce); const init = async () => { try { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab?.id) return; if (!window.google || !window.google.maps || !window.google.maps.places) { await chrome.scripting.executeScript({ target: { tabId: tab.id }, world: 'MAIN', files: ['inject/googlePlaces.js'], }); } } catch (error) { onLoadFailed(new Error(String(error))); } }; useEffect(() => { init(); }, []); return fetchSuggestions; };


用途:
page.tsx:

import { useGooglePlacesAutocomplete } from '@/library/hooks/useGooglePlaces'; export const Example = (props) => { const [autocompleteData, setAutocompleteData] = useState<google.maps.places.AutocompletePrediction[]>([]); const autocomplete = useGooglePlacesAutocomplete({ debounce: 300, minLengthAutocomplete: 3 }); return ( <> <input type='text' onChange={(e) => autocomplete(e.target.value, setAutocompleteData)} /> <ul> {autocompleteData.map((item, index) => <li key={index}>{item.description}</li>)} </ul> </> ); };

    
© www.soinside.com 2019 - 2024. All rights reserved.