ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ArcGIS JS API 3.39 SDK离线部署与常见问题排查指南

ArcGIS JS API 3.39 SDK离线部署与常见问题排查指南 简介面向Web GIS开发者与地理信息学习者的ArcGIS JavaScript API 3.39 SDK资源包用于构建支持地图展示、图层管理、空间分析及服务调用的交互式Web应用覆盖从入门到进阶的典型开发场景。压缩包共含2000个文件其中HTML示例页面有1522个便于直接演示各类功能配合JavaScript脚本与CSS样式表可快速理解API调用方式和页面布局另有大量PNG图标、GIF动图等视觉素材作为辅助说明整包约85.19MB可离线查阅与调试。内容涵盖地图与图层操作、几何对象与空间分析、地理编码与几何服务调用、符号化渲染、数据加载及安全认证机制并附带完整SDK文档与可运行示例帮助开发者随时定位功能并复用代码。已有140人学习该资源对GIS初学者是系统学习的好材料对有经验者则是便捷的离线开发参考。 说来也巧这篇文章的标题就是我电脑里那个真实文件的完整名字——arcgis_js_v339_sdk.zip。这包东西早几年还得从Esri官网挂账号下载3.39又是ArcGIS API for JavaScript 3.x系列的最后一个版本所以哪怕后来4.x已经更新到飞起这包还没真正“过气”。很多老GIS系统的维护者、政府内网项目的开发者、还在用ArcGIS Server 10.x接地图服务的团队手里都攥着这个zip。这篇文章我想把它彻底讲透这个包里面装了什么、怎么在离线环境本地化部署、那些高频报错背后到底怎么回事、以及它在4.x时代到底还能不能继续用。不整虚的就是把你拿到这个zip之后会遇到的问题按实际排查顺序捋一遍。1. v3.39的特殊身份3.x系列的收官版本为什么还有人在用1.1 3.x 和 4.x 到底差在哪很多人一上来就问ArcGIS JS API都出到4.x了为什么还搞3.x这个问题得从架构差异说起因为这不是简单的版本升级而是两套完全不同的东西。3.x走的是Dojo AMD加载体系API暴露成esri/map、esri/layers/ArcGISDynamicMapServiceLayer这种模块地图渲染底层依赖Canvas和DOM操作。4.x则是从底层重写Map、View、Layer全部分层渲染走WebGL3D能力也是从4.x才有的。我的直观感受是3.x像一台皮实的老式越野车你只要按规则操作没人会质疑它的可靠性4.x像新一代新能源车上限更高但很多零部件的脾气你也得重新摸。v3.39的特殊之处在于它是3.x系列最后一次更新算是这个分支的“最终形态”。官方后续不再给3.x加新功能但这反而让它在存量项目里显得珍贵——因为API稳定了不折腾了老系统反而能一直跑下去。1.2 谁的电脑里还留着这个zip包我自己归纳了一下还在下载和保留arcgis_js_v339_sdk.zip的人群基本是下面三类老系统维护者十年前用3.x建的地图网站现在还在地理信息中心或企业内网里跑着。这波人需要的不是新功能而是“原样复现”的部署包。内网/离线环境开发者机房物理隔离公网CDN根本访问不了必须把API库放到本地Web服务器里。zip包就是唯一的资源来源。从ArcGIS Desktop过渡到Web GIS的团队还在用ArcGIS Server发布动态地图服务用3.x的ArcGISDynamicMapServiceLayer接服务是整个工作流里最省事的一环。说白了3.39能不能用取决于你的业务场景。如果你的项目在公网、没有历史包袱那确实没必要用3.x但如果你要维护的就是一个不能随便换底座的存量系统那这个zip包就是你的救命稻草。2. 从zip包到一张地图本地化部署的完整实操2.1 解压后先搞清楚目录结构拿到arcgis_js_v339_sdk.zip第一步当然是解压。这里我强烈建议用7-Zip或者WinRAR新版本不太建议用Windows系统自带的“全部解压缩”因为SDK包内部文件多、路径深老版本资源管理器解压偶尔会漏文件或报路径过长。解压出来你会看到核心目录是arcgis_js_api再往下走是arcgis_js_api/ library/ 3.39/ 3.39/ init.js dojo/ dijit/ dojox/ esri/ util/这里有个细节3.39出现了两次这不算错误是Esri刻意保留的多级目录为了让IIS、Nginx这类Web服务器能直接映射多版本。不建议手动改动这一层目录结构否则init.js内部相对路径会全盘失效。init.js本质上是一个AMD加载器引导文件它会根据相对路径自动找到dojo、esri这些模块。所以部署时最重要的是保证init.js能被浏览器通过HTTP协议访问到而不是用file://直接打开页面。2.2 Nginx发布与页面引用的标准写法以Linux服务器为例把解压出来的arcgis_js_api整个目录放到Nginx的web根目录下比如/usr/share/nginx/html/arcgis/。然后确认配置里能正确访问server { listen 80; server_name localhost; root /usr/share/nginx/html; location /arcgis/ { add_header Access-Control-Allow-Origin *; } }重启Nginx后浏览器里访问http://localhost/arcgis/library/3.39/3.39/init.js应该能看到返回的JavaScript内容。接下来写页面。3.x在线引用的标准方式是script srchttps://js.arcgis.com/3.39//script本地部署则替换成link relstylesheet hrefhttp://localhost/arcgis/library/3.39/3.39/esri/css/esri.css link relstylesheet hrefhttp://localhost/arcgis/library/3.39/3.39/dijit/themes/tundra/tundra.css script srchttp://localhost/arcgis/library/3.39/3.39/init.js/script请注意样式表不是可选项而是必选项。很多人部署完发现页面白屏、地图区域没东西第一反应是JS出问题其实往往只是漏了esri.css。3.x的地图容器、弹窗、控件样式全在这套CSS里不引的话就算地图初始化成功UI也是碎的。2.3 dojoConfig部署时真正需要动脑的地方init.js加载之后会按AMD规范去加载依赖模块。如果你的API在本地、而页面在另一个域名下就必须显式配置dojoConfig里的packages把模块地址指向本地script var dojoConfig { async: true, packages: [ { name: esri, location: /arcgis/library/3.39/3.39/esri }, { name: dojo, location: /arcgis/library/3.39/3.39/dojo }, { name: dijit, location: /arcgis/library/3.39/3.39/dijit }, { name: dojox, location: /arcgis/library/3.39/3.39/dojox } ] }; /script script srchttp://localhost/arcgis/library/3.39/3.39/init.js/script然后就可以用require写地图代码了require([ esri/map, dojo/domReady! ], function(Map) { var map new Map(mapDiv, { basemap: streets, center: [116.39, 39.9], zoom: 10 }); });这里的dojo/domReady!不是写错它是Dojo的加载器插件表示DOM加载完后再执行回调。3.x开发里这个是标配不写的话经常出现地图容器还没渲染好就初始化的情况。3. 踩过的坑都在报错里常见错误排查链路3.1 白屏和加载失败先分清是路径问题还是依赖冲突我刚接触3.x本地部署时遇到最多的问题就是页面白屏控制台刷出一堆红色报错。后来总结出一个排查顺序能解决90%的问题第一步看浏览器Network面板里init.js状态码。如果404说明路径配置不对重点检查目录层级是否被改动、Nginx的root路径是否正确。第二步看Console里有没有define already defined或者Module esri/map failed to load这类报错。前者通常是因为页面里同时引入了jQuery、RequireJS等等其他加载器和Dojo的AMD机制冲突了后者多半是dojoConfig.packages里的路径写错模块找不到。有一个很迷惑的现象如果你在页面里引了init.js之后又引了其他带有define的库Dojo会直接罢工。3.x时代常见的组合是jQuery Dojo同时存在解决办法是优先让Dojo加载再把jQuery作为AMD模块接入或者干脆在Dojo加载前禁用jQuery的AMD支持。这也是个老坑了。3.2 CORS跨域file://和跨域请求的坑很多新手第一次部署时图方便直接双击本地HTML文件结果页面打不开地图。控制台报的是from origin null has been blocked by CORS policy这是因为浏览器把file://请求的origin视为null而Esri的API在加载底图、访问服务时都会发起XHR请求跨域就被拦了。解决方式没有魔法就是老老实实把页面放到Web服务器下通过HTTP访问。如果你只是API在A域名、页面在B域名则要在A域名的服务器上开启CORS。Nginx里加一行add_header Access-Control-Allow-Origin *;通常就够了。如果服务端不能改那就需要走代理我在第4节会专门讲。3.3 “could not find eocd”zip包损坏背后的问题热词里有一个很典型的错误信息invalid zip archive: could not find eocd。EOCD是ZIP文件末尾的一条中央目录记录如果解压工具找不到说明这个zip包大概率是损坏的或者根本不是完整的ZIP文件。我在实际项目里遇到过几种来源下载断点续传出错网络不稳定浏览器下载看似完成但文件体积比官方标注少几百KB。这种情况重新下载一般能解决。杀毒软件拦截公司电脑的杀毒软件把包内某些JS文件当风险文件隔离了结果是压缩包残缺。可以暂时关闭实时防护再解压或者把解压目录加入白名单。解压工具过旧老版本WinRAR偶尔不支持新压缩算法换7-Zip或最新版360压缩后再试。如果一个zip包反复下载、换了机器还是报eocd错误优先怀疑下载源的问题。找文件校验值MD5/SHA对比一下是判断包完不完整最稳妥的办法。3.4 图层加载不出来“范围不一致”的常见表现你可能会在部署完后遇到地图底图正常显示但业务图层请求报错或者显示位置不对的情况。热词里的“arcgis范围不一致”说的就是这类问题。原因通常是图层的全图范围fullExtent与当前地图视图的初始范围设置不一致。比如ArcGIS Server发布的服务是整个县的但页面初始化时center和zoom写的是另一个城市图层请求时会按服务自带范围裁剪视觉上就是“地图偏了”或者“图层缺失”。解决办法是在Map初始化时显式指定extent参数而不是分别指定center和zoomrequire([ esri/map, esri/geometry/Extent, dojo/domReady! ], function(Map, Extent) { var initExtent new Extent({ xmin: 116.0, ymin: 39.0, xmax: 117.0, ymax: 40.0, spatialReference: { wkid: 4326 } }); var map new Map(mapDiv, { extent: initExtent }); });这样地图容器会在加载完成后自动缩放到指定范围业务图层再添加进来时就会以这个范围为基准请求数据少掉很多莫名其妙的问题。4. 让老SDK发挥余热进阶用法与场景扩展4.1 SDK包自带samples最好的学习资料就在压缩包里arcgis_js_v339_sdk.zip里除了API库还带了一整套sdk文档和samples。很多人只取api目录把samples丢在一边非常可惜。samples目录里的示例是纯静态页面直接放到Web服务器下就能跑不需要额外的后端服务。里面每个demo都有完整的HTMLJS代码从加载底图、画点线面到查询属性、调用GP服务几乎是“抄作业”级别的教程。比如你想做一个搜索定位功能在samples里搜locator关键词找一个下载地址定位的示例把里面的url替换成自己的ArcGIS Server地址基本就通了。这个办法比我当年对着API Reference硬啃高效得多。不过提醒一句samples里很多示例默认走在线底图服务比如basemap: streets在纯内网环境是加载不出来的。如果底图也要求离线需要自己准备切片缓存或瓦片服务然后把basemap替换成自己的ArcGISTiledMapServiceLayer。4.2 代理配置解决跨域访问ArcGIS Server的经典方案如果说本地化部署是让API跑起来那么代理就是让API能真正用起来。ArcGIS Server服务可能位于http://192.168.1.100:6080/arcgis/rest/services和前端页面不在同一个域浏览器会有跨域限制。3.x时代的正解是配置esriConfig.defaults.io.proxyUrl。Esri官方提供了一套resource-proxy代理项目包含.NET、Java、PHP、Node.js等版本。原理是让前端请求先打到同域的代理页面由代理转发到ArcGIS Server再把结果返回给前端从而绕开浏览器的同源策略。使用方式很简单esriConfig.defaults.io.proxyUrl /proxy/proxy.jsp; esriConfig.defaults.io.alwaysUseProxy false;其中alwaysUseProxy建议设成false只有当请求URL不在CORS允许名单里时才走代理减少代理服务器的压力。我在实际项目里遇到过一个情况ArcGIS Server自带的CORS支持只对部分版本的WebAdaptor生效端口直连模式下跨域仍然受限。这种情况下与其折腾服务器配置不如直接用代理来得省心。4.3 跟外部表数据联动连接Excel这类数据源的另类思路热词里有一条“arcgis连接excel表格出现连接到数据库失败”这其实是ArcGIS Desktop/Pro的问题不是JS API的范畴。但在做Web GIS时很多人也会把Excel里的业务数据通过属性查询或FeatureLayer的方式挂到地图上。3.x里处理Excel数据我建议不要直接连数据库而是将Excel转成CSV或GeoJSON再用FeatureLayer加载。3.39对GeoJSON的支持虽然不是原生内置但可以利用第三方库解析后构造Graphic然后批量add到GraphicsLayer。这种方式比后端连库稳得多也不容易出现编码、类型转换的问题。我们曾经在一次巡检系统里把上千条设备台账从Excel转成GeoJSON前端用FeatureLayer渲染点图层查属性、弹窗、点击高亮全部搞定稳定跑了两三年。5. 留守还是迁移v3.39之后的技术路线选择5.1 什么情况下建议继续用3.39不要为了升级而升级。如果你所在的团队满足以下条件我认为继续留守3.39完全是合理选择系统稳定运行多年地图功能和业务耦合很深改动成本远大于收益开发环境是内网隔离无法使用CDN需要离线部署3.39的资源包很容易获得使用的服务是动态地图服务MapServer3.x的ArcGISDynamicMapServiceLayer直接用得顺手团队成员已习惯Dojo体系重新学4.x的架构和工作流需要时间成本。我见过太多项目折腾几个月从3.x迁到4.x最后发现核心功能还是那些点线面、查询、弹窗4.x带来的WebGL和3D能力根本没用到。这种迁移纯粹是技术债焦虑驱动的不值当。5.2 如果决定迁移4.x从哪里开始当然如果你的项目需要3D场景、海量数据前端渲染、或者要接入新版本Portal的WebMap那3.x确实力不从心迁移4.x就是必要的。迁移的第一个动作不是改代码而是读官方迁移文档里的模块对照表。3.x的esri/map对应4.x的esri/Map加esri/views/MapView3.x的esri/layers/ArcGISDynamicMapServiceLayer对应4.x的esri/layers/MapImageLayer3.x的esri/graphic对应4.x的esri/Graphic这个映射关系先搞明白后面才好动手。实际开发里4.x的代码风格也更接近现代前端require([ esri/Map, esri/views/MapView, esri/layers/MapImageLayer, dojo/domReady! ], function(Map, MapView, MapImageLayer) { var layer new MapImageLayer({ url: http://server/arcgis/rest/services/xxx/MapServer }); var map new Map({ layers: [layer] }); var view new MapView({ container: mapDiv, map: map, center: [116.39, 39.9], zoom: 10 }); });我的建议是如果只是简单功能迁移可以按“地图初始化、图层加载、符号渲染、弹窗交互”四个模块逐步替换一个一个验证。不要指望一次性把所有代码改完这种大动干戈的改动最稳妥的方式是并行维护一个4.x分支功能验证通过后再切换主版本。话说回来不管哪条路arcgis_js_v339_sdk.zip作为3.x时代的收官包在很长一段时间内都不会彻底退出历史舞台。我自己每次部署新环境时都会顺手留一个副本在服务器上保证手里始终有一份离线可用的API资源。哪怕哪天官方把旧版本下载入口彻底关掉这个zip也还能让那些跑在3.x上的系统继续活下去。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进