实现步骤
1. 登陆支付宝开放平台
支付宝开放平台链接:https://open.alipay.com
右侧直接支付宝扫码支付就完事了。
登陆之后需要填写入驻信息,如果是个人开发者的话可以切换一下信息,默认为系统服务商,可自行切换到开发者身份。如下图所示。
2. 进入沙箱环境
登陆成功后,如下图所示,页面往下拉,找到 开发服务 > 研发服务
这就是沙箱环境的入口了,接下来就是需要设置一下参数了。
3. 设置必要参数
第一个需要设置的参数为 RSA2(SHA256)密钥(推荐)
点击设置后,可以根据自己情况选择加密方式,下面我采用的是公钥:
下载安装支付宝开放平台开放助手,点击生成秘钥,公钥私钥都有用注意保存一下:
将生成的公钥复制到支付宝窗口中:
第二个需要设置的参数为 应用网关
开发环境网关链接为:https://openapi.alipaydev.com/gateway.do
4. 体验测试账户
沙箱环境提供了测试账户,包含商户号跟买家号,但是该账户只能在支付宝提供的测试APK上使用。
5.搭建工程
1)引入sdk依赖
<!--支付宝SDK依赖-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
2)创建AlipayConfig配置类,集中管理支付相关配置
package com.springboot.alipaydemo.config;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author ktz 2021/1/9
*/
public class AlipayConfig {
// 应用ID,您的APPID,收款账号即是您APPID对应的支付宝账号,开发时使用沙箱提供的APPID,生产环境改成自己的APPID
public static String APP_ID = "2016101100661033";
// 商户(应用)私钥(RSA2生成工具生成),您的PKCS8格式为RSA2
public static String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmMdQXsHvgTFeBX9YKM5lL75zIQ3OXXuyslXDFP0zKnx7/dR/Ij1/QktIiD1ZGj7stgZdNAIdM1VCLzLIvIciHmEP67COzZaf8lVYMBB+krnVUZrJSNcNVE6IdUjHfb83skSoMdmNF8GJe12gJWF5lTcbjovp4KDvptHRDr5OvlFcC2B6kbJZ1lvY0c8Y1CMHEqy2gmEM2f8ioglm0jra/9DD2leNGnJdknrQepbU+mtVmBnbSDsWwlE6NoShJEAWQGt3J2kD1iiriU0hVwxAqilLkGdHvZLbrU36ffBOnhrlAsj3FtucNox5KKuhcCmqSTEecsJaHcQarep7BBuhFAgMBAAECggEAWqnEMkgsy+fZtNI7ScVsU2ib9wQVAvbd1iiQJIqrsb2sg1+5vwe4FWiDCeGkB0pRqjmP+InZRaj5D8rTSbL8WjxOmYxIzY0fX0N4dYWqXYRurWR40zBRJxBW1/gHDQVJKUzny3SqI3VHtMV+E9sJY+pSHczDJtmMFapD4sjdoGJCUJVfYSiwnjVLDtsr4Zy0NtDy+uHLplixuFno4aYNxdZMIKkkJkxGOKAp8uiuI44daznOBYK1RJgL3oCOHoQyLS8lQslj+gI3HSZwYFjrzWJMc93itXqN7mkZ5QVOXe9UPoGHpNTk90a6kh/E/GR8iMxalHdqy4JStiwAOkINAQKBgQDg6yNWHqptoUATVrdTplCc/N9RkEY4YUDAG64Agul5SbzMzNNXRyYnoUN5raiXL/fwV+5OiIKOEv3RPAtmKCbE5HuukbJZQ/Jk+pdP/LcJnHVZhIUjeMbcpBwY6qmNzJLo00iPjeJ+8TtDDvpbILUU2uQjOhqLHq7Qy/x3PySxmQKBgQC9KTy3omZSQNltHmwAeMaJkwBRhlj78DIWO79RCMCu2vLsZAlt7ZZPpjXrFOpSJ6OElHyuVeptwOTK8r/FdSiabHxlVqPuxcUE3UTWjyusdc6skb6Q4Yb43FURZgGHQ6A40D4oh7Usnu2oTNDzrqJuiiV/ScSfEK1fOmkzNKYvjQKBgQCKTo2QK5NJjtrECZL6EU+I+capdTp4+PTELUE2d0nyl3FNzrY2+T1xKS1A6ZS+Q3UHikq0aCVAEFWcEHxB+Xa9pHKZymYNlka76YyaVyCG/Hr87Qyh32cJzrCoccSJub6tBR+dhvY8cUKr3c39s4Mmq+OV9ejUm62MH6PEAEQkIQKBgQCDZ901GE0KgOBKLGMMpNoPAh6rg6/XPNIendzW10S7c4Bj9U6TngPYSveT2lC5R64RUPGYTjjvi5uk3KOZ8TyGoix8XYa+PYcTTP8gKg9F3AT53rlKflE8GhvCXWFcbP8l2IwFrdiPKcyhKNPTJJLURYWs+jrr4TL/P12LY9y6lQKBgElazuCMKJ+soUdycSV0fdpFbMxTPH/mbilm9CILKIk82Jhv2glj6FTsSAaGaXgJ8wpULaQzHWRwizrPTsW1NVI53/7II/zP8yGnEul/VBNtUENzwPXYKzQ30MPkqj4dA1Nm7LK3tAdpHIULlUIH+czbQoW0s2hSM+3uSMSMaYw8";
// 支付宝公钥(支付宝生成),查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApuwI5C81TnfLu4ql77w3FdgBCHss7GHQqpzVqwGDZkOMyKRvKGX7oWJtRYDX6I5c0n1hEtnOcG0lo5jT6tYldqRI2k7UxZLmOez2PZfA/q9wrKp2RwgiR3KSS7mS9x13IDpL5OIXADByYtjqQG3TnMGbgo4SXv0eju8qG3Vf13fwicyjs+BWfTXHFZwz8a5YyDxuCIdUL+7KYackxT2MmLmLD0FeN8fXp6iLVJmfAXuKKW95FA8X/FjbLrFtS3OtUpQcp6UBUpRhcHEIMtbTTyHsvTzAqImgsEgdaexNZgSuX/qFSNv7Q65gByThAOinfZZmQltDLy34AEh9FhAmZwIDAQAB";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
// 请确保url中的域名和IP是外网可以访问的,且不能填写localhost、127.0.0.1、192.168.x.x等本地或内网IP
public static String notify_url = "http://p3hx94.natappfree.cc/notify";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问(其实就是支付成功后返回的页面)
// 请确保url中的域名和IP是外网可以访问的,且不能填写localhost、127.0.0.1、192.168.x.x等本地或内网IP
public static String return_url = "http://p3hx94.natappfree.cc/return";
// 如果支付宝成功通知页面路径无法跳转,模拟可用跳转地址进行测试
// public static String return_url = "http://www.baidu.com";
// public static String return_url = "http://127.0.0.1:8080/return";
// 签名方式
public static String sign_type = "RSA2";
// 字符编码格式
public static String CHARSET = "utf-8";
// 支付宝网关,这是沙箱的网关(沙箱接口,正式上线时请改用正式支付接口)
public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
// 支付宝网关
public static String log_path = "C:\\";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3)编写控制层代码,创建PayController类
package com.springboot.alipaydemo.controller;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.springboot.alipaydemo.config.AlipayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @author ktz 2021/1/9
*/
@Slf4j
@Controller
public class PayController {
/***
* ktz 2021/1/11 13:45
* 支付网站扫码支付接口-统一下单支付接口
* @param request
* @param response
* @return void
*/
@ResponseBody
@RequestMapping("/pay")
public void payController(HttpServletRequest request, HttpServletResponse response) throws IOException {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.sign_type);
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金额,必填
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
//订单名称,必填
System.out.println(request.getParameter("subject"));
String subject = request.getParameter("subject");
//商品描述,可空
String body = new String(request.getParameter("body").getBytes("ISO-8859-1"),"UTF-8");
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//若想给BizContent增加其他可选请求参数,以增加自定义超时时间参数timeout_express来举例说明
//alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
// + "\"total_amount\":\""+ total_amount +"\","
// + "\"subject\":\""+ subject +"\","
// + "\"body\":\""+ body +"\","
// + "\"timeout_express\":\"10m\","
// + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节
//请求
String form="";
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
response.getWriter().write(form);//直接将完整的表单html输出到页面
response.getWriter().flush();
response.getWriter().close();
}
/***
* ktz 2021/1/11 13:48
* 支付宝服务器异步通知页面-支付成功后支付宝通知
* @param request
* @param out_trade_no
* @param trade_no
* @param trade_status
* @return java.lang.String
*/
@PostMapping("/notify")
@ResponseBody
public String alipayNotify(HttpServletRequest request, String out_trade_no, String trade_no, String trade_status) throws Exception {
Map<String, String> params = getParamsMap(request);
log.info("notify params: {}", JSONObject.toJSON(params));
// 验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, "utf-8", "RSA2");
log.info("notify signVerified: {}", signVerified);
if (signVerified) {
//处理你的业务逻辑,更细订单状态等
return ("success");
} else {
log.info("验证失败,不去更新状态");
return ("fail");
}
}
/***
* ktz 2021/1/11 13:47
* 支付宝服务器同步通知页面-支付成功后回跳
* @param request
* @param out_trade_no
* @param trade_no
* @param total_amount
* @return java.lang.String
*/
@GetMapping("/return")
@ResponseBody
public String alipayReturn(HttpServletRequest request, String out_trade_no,String trade_no,String total_amount) throws Exception {
Map<String, String> params = getParamsMap(request);
log.info("return params: {}", JSONObject.toJSON(params));
// 验证签名(支付宝公钥返回true)
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY,"utf-8", "RSA2");
log.info("return signVerified: {}", signVerified);
if (signVerified) {
return ("success");
} else {
log.info("验证失败,不去更新状态");
return ("fail");
}
// return "return_url";
}
/***
* ktz 2021/1/11 13:51
* 获取请求参数
* @param request
* @return java.util.Map<java.lang.String,java.lang.String>
*/
private Map<String, String> getParamsMap(HttpServletRequest request) throws Exception {
Map<String,String> params = new HashMap<>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
try {
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
} catch (Exception e) {
e.printStackTrace();
}
}
return params;
}
@RequestMapping("/index")
public String toTest(){
return "index";
}
}
4)其它依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.33</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jsp支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- servlet 依赖包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
5)配置springmvc的映射路径
# 配置springmvc映射路径(@RestController包含的@ResponseBody不走视图解析器,所以一般配合@Controller使用)
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
6)模拟订单页 index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<form action="/pay" method="post">
<!--required 非空-->
商户订单号:<input type="text" name="out_trade_no" required><br/>
订单名称:<input type="text" name="subject" required><br/>
交易金额:<input type="text" name="total_amount" required><br/>
订单描述:<input type="text" name="body"><br/>
<input type="submit" value="下单"> <input type="reset" value="重置">
</form>
7)模拟异步通知页 notify_url.jsp
<%@page import="com.alipay.api.internal.util.AlipaySignature"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.springboot.alipaydemo.config.*"%>
<%
//获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
//计算得出通知验证结果
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
if(verify_result){//验证成功
//
//请在这里加上商户的业务逻辑程序代码
//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
if(trade_status.equals("TRADE_FINISHED")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
} else if (trade_status.equals("TRADE_SUCCESS")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
}
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
out.clear();
out.println("success"); //请不要修改或删除
//
}else{//验证失败
out.println("fail");
}
%>
8)模拟同步回跳页 return_url.jsp
<%@page import="com.alipay.api.internal.util.AlipaySignature"%>
<%
/* *
功能:支付宝页面跳转同步通知页面
版本:3.2
日期:2011-03-17
说明:
以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
//***********页面功能说明***********
该页面可在本机电脑测试
可放入HTML等美化页面的代码、商户业务逻辑程序代码
TRADE_FINISHED(表示交易已经成功结束,并不能再对该交易做后续操作);
TRADE_SUCCESS(表示交易已经成功结束,可以对该交易做后续操作,如:分润、退款等);
//********************************
* */
%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.springboot.alipaydemo.config.*"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>支付宝页面跳转同步通知页面</title>
</head>
<body>
<%
//获取支付宝GET过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
//计算得出通知验证结果
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
if(verify_result){//验证成功
//
//请在这里加上商户的业务逻辑程序代码
//该页面可做页面美工编辑
out.clear();
out.println("验证成功<br />");
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
//
}else{
//该页面可做页面美工编辑
out.clear();
out.println("验证失败");
}
%>
</body>
</html>
注意:异步回调和同步回跳可以在控制层模拟!
RSA生成器下载地址
生成的商户应用公钥和私钥需要保存.
https://opendocs.alipay.com/open/291/105971
应用申请位置
搭建后进行测试,可能遇到以下几个问题
1.支付宝沙箱环境提示支付存在钓鱼风险
解决方案:
1)切换浏览器(我用的是谷歌和火狐)
2)清除浏览器cookie及网站数据
2.网络异常(反复重试即可)
3.订单异常(订单号重复)
4.回调和同步功能无法实现,出现404(内网穿透下)
natapp实现内网穿透
在对接支付宝或微信支付等支付平台时,基本都需要进行回调接口的联调。而我们在进行本地开发时,本地的内网地址是无法被外网访问的,那么支付平台的服务器就无法回调我们的接口地址。所以我们需要做一个内网穿透,才能让外网能够访问到我们内网的接口地址。
综上所述,内网穿透就是干这么一件事的,它让外网的机器能访问到我们内网的接口地址。例如我们在本地开发好了一个网站,想要分享给朋友看,但是他不能直接访问到我们机器上的内网地址,那么就我们需要做一个内网穿透,然后他就能访问到我们的内网地址了。简单的说,通过内网穿透,实现外网域名访问内网资源,比如我们的服务接口。
内网映射
内网映射是一种NAT地址转换,也就是把在内网中的IP转换成公网IP。为了便于访问还能将变化的公网IP绑定到一个固定的域名上去,这样外网的人就能通过这个固定域名来访问内网了。例如http://xxx.ssca.club 指向我本地的 http://127.0.0.1:port。通俗的理解,内网映射就是将内网映射到外网,实现通过外网链接从而访问本地的效果。
natapp官网
https://natapp.cn/
完整Demo
链接:https://pan.baidu.com/s/1m_DY87F4lDk3rYMk2YvpVg
提取码:ktz1