使用 alipay-easysdk 时支付宝支付二维码无法显示
结论
alipay-easysdk 的当面付预创建接口返回的是二维码内容字符串,也就是 qr_code,并非二维码图片。浏览器直接输出该字符串时,不会自动显示二维码。需要使用 ZXing 或前端二维码组件,将字符串编码为图片。
如果 qr_code 为空,问题不在图片显示环节。应先查看支付宝接口返回的 code、sub_code 和 sub_msg,再检查应用配置、签名密钥、支付产品权限,以及生产环境和沙箱环境是否匹配。
正确的处理流程
先调用当面付预创建接口:
AlipayTradePrecreateResponse response =
Factory.Payment.FaceToFace().preCreate(
"测试商品",
"ORDER_202609090001",
"0.01"
);
接口调用成功后,获取二维码内容:
String qrContent = response.getQrCode();
qrContent 通常是需要写入二维码的地址。它不是图片 URL,不能直接放进 <img src="">。正确的流程是:
调用 preCreate
↓
检查支付宝返回码
↓
取得 response.getQrCode()
↓
使用二维码库生成 PNG/SVG
↓
返回给浏览器显示
先确认支付宝接口调用成功
仅检查 response 是否为 null 不够,还需要记录完整的错误信息:
AlipayTradePrecreateResponse response =
Factory.Payment.FaceToFace().preCreate(
"测试商品",
orderNo,
"0.01"
);
if (response == null) {
throw new IllegalStateException("支付宝接口未返回结果");
}
if (!"10000".equals(response.getCode())) {
throw new IllegalStateException(
"支付宝下单失败,code=" + response.getCode()
+ ", msg=" + response.getMsg()
+ ", subCode=" + response.getSubCode()
+ ", subMsg=" + response.getSubMsg()
);
}
String qrContent = response.getQrCode();
if (qrContent == null || qrContent.trim().isEmpty()) {
throw new IllegalStateException("支付宝接口调用成功,但未返回 qr_code");
}
确认 code 为 10000,并且 qrContent 非空后,再生成二维码图片。
使用 ZXing 生成二维码图片
项目需要引入 ZXing 的 core 和 javase 模块。具体版本应结合项目使用的 JDK、Spring Boot 版本和现有依赖管理来确定。排查二维码问题时,没有必要反复更换 alipay-easysdk 版本。
二维码生成方法如下:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class QrCodeUtils {
public static byte[] createPng(String content, int width, int height)
throws Exception {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix matrix = new QRCodeWriter().encode(
content,
BarcodeFormat.QR_CODE,
width,
height,
hints
);
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
MatrixToImageWriter.writeToStream(matrix, "PNG", output);
return output.toByteArray();
}
}
}
在 Spring Boot 中,可以直接返回 PNG 图片:
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.UUID;
@RestController
public class AlipayController {
@GetMapping(
value = "/alipay/qr",
produces = MediaType.IMAGE_PNG_VALUE
)
public ResponseEntity<byte[]> createQrCode() throws Exception {
String orderNo = UUID.randomUUID().toString().replace("-", "");
String totalAmount = new BigDecimal("0.01").toPlainString();
AlipayTradePrecreateResponse response =
Factory.Payment.FaceToFace().preCreate(
"测试商品",
orderNo,
totalAmount
);
if (!"10000".equals(response.getCode())) {
throw new IllegalStateException(
"支付宝下单失败:"
+ response.getSubCode()
+ " - "
+ response.getSubMsg()
);
}
String qrContent = response.getQrCode();
if (qrContent == null || qrContent.trim().isEmpty()) {
throw new IllegalStateException("支付宝未返回二维码内容");
}
byte[] image = QrCodeUtils.createPng(qrContent, 300, 300);
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.body(image);
}
}
浏览器访问 /alipay/qr 后,会直接收到一张 PNG 图片。
如果前后端分离
后端也可以只返回 qrCode 字符串:
return Map.of(
"orderNo", orderNo,
"qrCode", response.getQrCode()
);
前端拿到字符串后,再通过二维码组件生成图片。下面这种写法通常无法正确显示:
<img src="支付宝返回的 qr_code">
原因是 qr_code 表示二维码需要承载的内容,并不是浏览器可以直接加载的图片地址。
检查 EasySDK 初始化配置
如果 response.getQrCode() 为空或接口报错,需要确认 SDK 已在调用支付接口前完成初始化:
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
config.appId = "你的应用 AppId";
config.merchantPrivateKey = "应用私钥";
config.alipayPublicKey = "支付宝公钥";
Factory.setOptions(config);
检查以下配置:
merchantPrivateKey应填写应用私钥,不能填写支付宝公钥。alipayPublicKey应填写支付宝公钥,不能填写应用公钥。- 确认密钥内容没有被换行、空格或配置文件转义破坏。
- 沙箱应用、沙箱账号和沙箱网关需要配套使用。
- 生产应用不能使用沙箱网关或沙箱密钥。
- 应用需要开通并具备相应的当面付能力。
- 如果使用证书模式,应按证书模式配置,不能与普通公钥模式混用。
不要在公开日志中打印私钥、完整接口响应或用户付款地址。
确认调用了正确的接口
如果需要在商家页面展示收款二维码,应调用当面付预创建接口:
Factory.Payment.FaceToFace().preCreate(...)
如果调用的是电脑网站支付,例如:
Factory.Payment.Page().pay(...)
接口通常返回支付宝收银台需要的表单或页面内容,处理方式与当面付不同。此时应把返回的表单内容交给浏览器,不能通过读取 qrCode 自行生成图片。
仍然无法显示时的排查顺序
- 记录
code、msg、subCode和subMsg,确认支付宝接口是否调用成功。 - 检查
response.getQrCode()是否为空。 - 如果不为空,通过日志或调试器确认字符串是否完整。
- 使用 ZXing 单独为固定文本生成二维码,确认图片输出接口正常。
- 检查 HTTP 响应的
Content-Type是否为image/png。 - 检查前端是否把 JSON 响应当成图片,或者误将
qrCode放进<img src="">。 - 确认订单号没有重复、金额格式正确,并查看支付宝返回的具体业务错误。
- 最后检查应用权限、网关、AppId 和密钥配置。
反复切换 alipay-easysdk 版本,通常无法解决二维码显示问题。排查时应先判断属于哪种情况:支付宝没有返回 qr_code,还是已经返回 qr_code,但应用没有将其生成二维码图片。
备注:内容仅供参考。
