调用百度地图API报错‘211’ sn 校验失败

本文记录了在Python 3.6中使用百度地图API遇到的问题及解决办法。遇到的问题包括APP服务被禁用和APP SN校验失败。前者是API服务代码修改所致,后者是Python 2.x和3.x中文编码不同造成。解决办法是用Python 2.x的转码结果替换3.x的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近日在Python 3.6中尝试了一下百度地图API,遇到一些问题,已经解决,在此记录,希望能给同惑者带来帮助。

先说问题:

1,尝试百度地图API的sn计算示例,遇到错误——{'status': 240, 'message': 'APP 服务被禁用'}

2,解决上述问题后,遇到新错误——{'status': 211, 'message': 'APP SN校验失败'}

上代码,这是地理编码的请求,即通过传递参数“百度大厦”获取对应的经纬度,默认百度坐标系。

# -*- coding: utf-8 -*- 
# 第一行必须有,否则报中文字符非ascii码错误
import urllib
import hashlib

# 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak
queryStr = '/geocoder/v2/?address=百度大厦&output=json&ak=yourak'

# 对queryStr进行转码,safe内的保留字符不转换
encodedStr = urllib.quote(queryStr, safe="/:=&?#+!$,;'@()*[]")

# 在最后直接追加上yoursk
rawStr = encodedStr + 'yoursk'

# md5计算出的sn值7de5a22212ffaa9e326444c75a58f9a0
# 最终合法请求url是http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak&sn=7de5a22212ffaa9e326444c75a58f9a0
print hashlib.md5(urllib.quote_plus(rawStr)).hexdigest()

解决方案:

问题分析:

首先检查了一下控制台,发现所有可用服务都开启了。

没看出哪里有问题,后来偶然看到别的地理编码的请求方式和这个例子有点区别。区别如下:

http://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocation

这里“/geocoding/v3”和上面示例代码的[queryStr = '/geocoder/v2/?address=百度大厦&output=json&ak=yourak']开头部分"/geocoder/v2/"不一样。替换之后没有在报错——{'status': 240, 'message': 'APP 服务被禁用'}。这里应该是API自身的服务代码做了修改,即废除了“/geocoder/v2/”替换为"/geocoding/v3"。

再说说第二个问题,sn校验失败就是说url请求传送到服务器后计算出的sn和我在本地计算的sn不一样。先看本地代码。

# _*_ encoding='utf-8' _*_

from urllib.request import urlopen, quote
from urllib import parse
from bs4 import BeautifulSoup
import requests
import hashlib
import json
    
if __name__=="__main__":
    home_url=r'http://api.map.baidu.com'
    # ak 和 sk 用数字0和6替换了,非真实
    my_ak='RVh62gHLF000000000000GyrG2uf34Gb'
    my_sk='0YWDV66666666666666rSwkjvy1YYo3D'
    # 以get请求为例http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak
    queryStr = r'/geocoding/v3/?address=百度大厦&output=json&ak=RVh62gHLF000000000000GyrG2uf34Gb'

    # 对queryStr进行转码,safe内的保留字符不转换
    encodedStr = quote(queryStr, safe="/:=&?#+!$,;'@()*[]")
    print(encodedStr)

    # 在最后直接追加上yoursk
    rawStr = encodedStr + my_sk
    print(rawStr.encode('utf-8'))
    print(quote(rawStr).encode('utf-8'))

    #下面这行注释过的代码会报错,因为hashlib.md5('这里是瞒足某种编码的二进制码')
    #print(hashlib.md5(parse.quote(rawStr)).hexdigest())
    md = hashlib.md5()     #获取一个md5加密算法对象
    md.update(quote(rawStr).encode('utf-8'))   #制定需要加密的字符串
    sn=md.hexdigest()

两次计算的sn不同,有两种可能的原因:

1,本地hashlib.md5()的输入与服务器端hashlib.md5()的输入不同

2,Python 2.x和3.x 版本下hashlib.md5()的计算方式不同

验证阶段:

分别向两个版本下的hashlib.md5()输入了同样的数据,所得结果一样。看来不是第一种可能。

实际上Python 3.x中urllib下没有直接的quote(),即无法使用urllib.quote()。quote('特殊字符,比如中文')可将特殊字符进行url编码,

以防传输到服务器端变成乱码。这个编码功能到了urllib的两个子模块中urllib.requesturllib.parse里面,功能一样。经过测试发现

Python 2.x中quote()会将一个中文编码为两个十六进制码,而Python 3.x中会将一个中文编码为三个十六进制码。

#Python 2.x
import urllib
print quote('百度大厦')
%B0%D9%B6%C8%B4%F3%CF%C3  #长度8


#Python 3.x
from urllib.parse import quote
print(quote('百度大厦'))
%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6  #长度12

正是这个编码的区别使得我们在本地计算sn时url的中文转码和服务器端计算sn时的中文转码不同,因而得到不同的sn

解决方法:

用Python 2.x的quote()转码结果替换3.x的转码结果,或者直接在Python 2.x中计算sn,再拿到3.x的程序中用。毕竟,

我们不能改变服务器端的计算,只好去适应它。多说一句,今天安装Python 2.7.12时看到提示,大意是2020年起,Python 2.x

版本的服务将逐步停止,也许百度地图API的服务器端很快就要用3.x的计算结果了。到时候,我们这些API调用者就可以直接使用本地

计算的sn了。

最终url【http://api.map.baidu.com/geocoding/v3/?address=%B0%D9%B6%C8%B4%F3%CF%C3&output=json&ak=RVh62gHLFZjX345Yx7MlQGyrG2uf34Gb&sn=08ae4326e1758ba537b24516815ee6fc】,将这个链接在浏览器中打开可看到:

{"status":0,"result":{"location":{"lng":116.30695597357377,"lat":40.05738753357608},"precise":1,"confidence":80,"comprehension":100,"level":"商务大厦"}}

到此,已完成本文的工作!

 

<think>好的,用户之前问过关于uniapp中web-view组件报错的问题,现在又询问如何在APP端使用web-view进行打印。我需要先回顾之前的对话,确保这次的回答保持连贯。 用户当前的疑问是关于打印功能的实现。首先,我需要考虑在APP端,尤其是使用web-view的情况下,如何实现打印。通常,移动端APP的打印功能可能不如网页端直接,因为涉及到设备硬件的调用,比如连接打印机的方式、系统API的支持等。 接下来,我需要分析可能的解决方案。首先,用户可能已经通过web-view加载了一个网页,这个网页可能需要调用打印功能。这时候,可能需要用到JavaScript的window.print()方法,但移动端的浏览器可能不支持或者行为不一致,尤其是在APP的web-view环境中。 然后,考虑原生插件。uniapp本身可能没有直接支持打印的API,但可以通过原生插件来实现。比如,使用Android的打印框架或iOS的AirPrint,这需要开发原生插件,或者使用现有的第三方插件,如uni-app的native.js,或者社区提供的插件。 另外,用户可能希望通过Web内容触发打印,这时候可能需要与原生代码进行通信,比如通过uni-app的uni.postMessage和onMessage方法,将打印指令发送到原生端,再由原生代码处理打印任务。 云打印也是一个可能的方案,特别是如果用户需要网络打印的话,可以调用第三方云打印服务的API,比如通过HTTP请求将内容发送到云打印机。 此外,用户可能需要打印PDF或其他格式的文件,这时候需要生成文件并调用系统的打印功能。例如,使用pdf-lib生成PDF文件,然后通过原生插件打开系统的打印对话框。 在安全性方面,需要提醒用户处理打印内容时要防止注入攻击,确保传输的数据经过校验。同时,不同平台(Android和iOS)可能有不同的实现方式,需要进行兼容性处理,比如使用条件编译。 用户可能需要具体的代码示例,比如如何在web-view中使用JavaScript调用打印,或者如何集成原生插件。需要给出清晰的步骤和示例代码,帮助用户一步步实现。 还要考虑用户的实际场景,比如他们是在企业内部使用,还是面向公众的APP,不同的场景可能适合不同的打印方案。比如,企业内部可能有特定的网络打印机,而公众用户可能需要更通用的解决方案。 最后,需要总结各种方法的优缺点,帮助用户根据自身情况选择最合适的方案,并提醒测试和调试的重要性,尤其是在真机环境下。</think>以下是针对 **uniapp 中 `web-view` 组件在 APP 端实现打印功能**的详细解决方案,涵盖常见场景和技术要点: --- ### **一、核心实现思路** 在 APP 端通过 `web-view` 打印,本质是通过 Web 内容触发设备打印能力。常见方案如下: | **方案** | **适用场景** | **优缺点** | |-----------------------|----------------------------------|---------------------------------------------| | **JavaScript 打印** | 简单网页内容打印(如HTML表格) | 依赖 WebView 环境,兼容性差(Android/iOS 支持不一) | | **原生插件调用** | 需要连接蓝牙/网络打印机 | 功能强大,需原生开发或集成第三方插件 | | **云打印API** | 远程打印(如快递单、小票) | 依赖网络,需对接第三方服务(如顺丰、菜鸟) | | **PDF生成+系统打印** | 复杂格式文档(如合同、报表) | 格式稳定,需处理文件生成与系统打印流程 | --- ### **二、具体实现步骤** #### **1. JavaScript 打印(基础方案)** 通过 `web-view` 加载的网页内调用 `window.print()` 方法,**仅限 Android 且需系统浏览器支持**: ```html <!-- 在 web-view 加载的 HTML 页面中 --> <button onclick="window.print()">打印网页内容</button> ``` **注意事项**: - **iOS 限制**:iOS WebView 默认禁用 `window.print()`,需原生层拦截处理。 - **样式适配**:通过 `@media print` 定义打印专用样式: ```css @media print { .noprint { display: none; } /* 隐藏非打印元素 */ body { font-size: 12pt; } /* 调整打印字体 */ } ``` --- #### **2. 原生插件集成(推荐方案)** 通过 `uni.requireNativePlugin` 调用原生打印能力,**需开发或使用现有插件**: ##### **步骤 1:安装打印插件** - 市场插件:搜索 `uni-app 打印插件`(如 [H5-Printer](https://ext.dcloud.net.cn/plugin?id=6895)) - 自定义插件:基于 Android `PrintManager` 或 iOS `UIPrintInteractionController` 开发 ##### **步骤 2:代码示例** ```javascript // 在 uni-app 的 Vue 页面中 const printer = uni.requireNativePlugin('H5-Printer'); export default { methods: { printPDF() { // 方式1:打印网页内容 const webview = this.$refs.webview; // 获取 web-view 组件实例 webview.print({ title: '销售订单' }); // 调用原生打印 // 方式2:打印本地文件 printer.printFile({ path: '/storage/emulated/0/Download/file.pdf', copies: 2 // 打印份数 }); } } } ``` --- #### **3. 云打印API对接** 通过 HTTP 请求将数据发送至云打印服务(如**支付宝云打印**、**飞鹅打印机**): ```javascript uni.request({ url: 'https://cloudprint-api.com/send', method: 'POST', data: { content: '<CA>测试小票</CA><QR>https://example.com</QR>', // 打印内容(支持HTML/指令) sn: '打印机编号' // 从服务商处获取 }, success: (res) => { console.log('云打印任务ID:', res.task_id); } }); ``` --- #### **4. PDF生成 + 系统打印(完整流程)** ##### **步骤 1:生成PDF文件** 使用 `pdf-lib` 或 `html2pdf.js` 库生成 PDF: ```javascript // 在 web-view 页面中 import { PDFDocument } from 'pdf-lib'; async function createPDF() { const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); page.drawText('Hello World!', { x: 50, y: 500 }); const pdfBytes = await pdfDoc.save(); return pdfBytes; // 转换为 Base64 或文件路径 } ``` ##### **步骤 2:调用原生打印** 通过插件或 `uni.downloadFile` + `uni.openDocument` 触发系统打印: ```javascript uni.downloadFile({ url: 'https://example.com/file.pdf', success: (res) => { uni.openDocument({ filePath: res.tempFilePath, showMenu: true, // 显示系统菜单(含打印选项) success: () => console.log('文档打开成功') }); } }); ``` --- ### **三、关键问题与优化** #### **1. 跨平台兼容性处理** - **条件编译**区分 Android/iOS: ```javascript // #ifdef APP-ANDROID androidPrinter.print(content); // #endif // #ifdef APP-IOS iosAirPrint(content); // #endif ``` #### **2. 安全增强** - **内容过滤**:防止恶意代码注入: ```javascript const sanitizedHTML = content.replace(/<script.*?>.*?<\/script>/gi, ''); ``` #### **3. 性能优化** - **缓存策略**:对重复打印内容使用本地缓存: ```javascript const cacheKey = 'print_template_v1'; uni.setStorageSync(cacheKey, templateHTML); ``` --- ### **四、调试技巧** 1. **真机日志**:使用 `adb logcat` (Android) 或 Xcode 控制台 (iOS) 查看原生层错误。 2. **WebView 调试**: ```javascript // 启用 WebView 调试(Android) if (uni.getSystemInfoSync().platform === 'android') { webview.setWebContentsDebuggingEnabled(true); } ``` 通过上述方案,可覆盖从简单网页打印到专业设备连接的多样化需求。实际开发中建议优先评估业务场景,选择成本与效果平衡的方案。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值