ArcGIS JS API 4.27:使用Base64图片仍触发PictureMarkerSymbol非法Blob访问
问题背景:在ArcGIS JS API 4.27中,无论使用本地图片路径还是Base64字符串设置PictureMarkerSymbol的url属性,API都会强制将其转换为Blob格式。如果服务器的内容安全策略(CSP)未显式允许blob:协议,就会触发如下错误:
Refused to load the image
'blob:https://www.myserver.com/953e5424-d924-2c3a-92b4-4cf83c376042'
because it violates the following Content Security Policy directive:
"img-src * data:". Note that '*' matches only URLs with network
schemes ('http', 'https', 'ws', 'wss'), or URLs whose scheme matchesself's scheme. The scheme 'blob:' must be added explicitly.
由于无法修改服务器CSP,可通过以下方案解决:
1. 降级API版本至4.26及以下
ArcGIS JS API 4.27才引入强制转换Blob的逻辑,4.26及更早版本会直接使用原始的图片URL或Base64字符串,不会触发Blob相关的CSP限制。如果项目对4.27的新特性没有依赖,这是最直接的解决方案。
2. 改用SVG格式的标记符号
将PNG图片转换为SVG格式,使用SVG的Data URI作为PictureMarkerSymbol的url值。API不会将SVG的Data URI转换为Blob,因此可以绕过CSP限制。
示例代码:
const mySymbol = { type: "picture-marker", url: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='48' height='48'><!-- 替换为你的SVG内容 --></svg>", width: "48px", height: "48px" };
如果是简单图标,可直接手写SVG代码;复杂图标可通过在线工具将PNG转成SVG后再使用。
3. 自定义符号渲染逻辑(高级方案)
利用ArcGIS JS API的自定义符号能力,手动实现图片渲染逻辑,跳过API的Blob转换步骤。
示例思路:通过继承Symbol类重写渲染方法,直接使用原始图片资源绘制到Canvas上:
class CustomPictureSymbol extends esri.symbol.Symbol { constructor(properties) { super(properties); this.url = properties.url; this.width = properties.width || "48px"; this.height = properties.height || "48px"; this._img = new Image(); this._img.src = this.url; } render(renderParams) { const ctx = renderParams.context; const sizeX = parseInt(this.width); const sizeY = parseInt(this.height); // 确保图片加载完成后再绘制 if (this._img.complete) { ctx.drawImage(this._img, -sizeX/2, -sizeY/2, sizeX, sizeY); } else { this._img.onload = () => { ctx.drawImage(this._img, -sizeX/2, -sizeY/2, sizeX, sizeY); }; } } } // 使用自定义符号 const mySymbol = new CustomPictureSymbol({ url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34...", // 你的Base64字符串 width: "48px", height: "48px" });
注意:这种方案需要熟悉API的符号渲染机制,需处理图片异步加载、渲染上下文等细节。
内容的提问来源于stack exchange,提问作者Robert Smith

