支付对接流程分析

当完成一个支付请求被发送到支付渠道方,支付渠道会很快返回一个结果。但是这个结果,只是告诉你调用成功了,不是扣款成功,这叫同步调用。很多人拿这个结果当作支付成功了,那就会被坑死,结果就是支付成功率特别高,伴随着一堆无法解释的坏账率,测试人员尤其要注意测试数据的篡改:金额,同步返回结果,订单号等。

同步请求参数里面会有一个回调地址,这个地址是支付渠道在扣款成功后调用的,这叫异步调用。一般同步接口仅检查参数是否正确,签名是否无误等。异步接口才告诉你扣款结果。一般异步接口有5秒以内的延迟。调用不成功会重试。有时候是这边成功了,但支付渠道侧没收到返回,于是会继续调。当天的支付到第二天还在被异步调用也都是正常的。这也是开发人员需要特别注意的地方,不要当做重复支付。测试人员也要对重复回调进行测试,应只有一次有效。这还不是最坑的,一般支付渠道侧,只有支付成功了才通知你。要是支付失败了,压根儿都不告诉你。 另一方面,如何老收不到异步结果呢?那就得查查了。同步结果不可靠,异步调用不可靠,那怎么确定支付结果?最终的杀招就是查单了,反查,一般支付渠道侧都会提供反查接口,定时获取DB中待支付的订单调用支付渠道侧的反查接口,最终把支付渠道侧扣款成功的订单完成掉。

来源:https://www.cnblogs.com/Alexr/p/9385650.html

 

 

对比

ID

微信需要三个ID:AppID、AppSecret、PID

支付宝需要亮哥ID:AppID、PID

多平台跳转

微信过于分散,从开放平台就不容易跳转到商户平台

蚂蚁金服集中的比较好,各平台互相跳转地很舒服

引用

微信使用gradle引用;支付宝使用jar包引用

登录

微信登录已经集成在ShareSDK了;支付宝没有集成

支付

双方都要求以服务器收到的信息为准,但是微信要求的更彻底,微信的返回值连订单号都没有

调微信App支付时,你的App不知道订单号(预交易订单号不是订单号);调支付宝App支付时,你的App知道订单号(而且知道详细的交易信息)

微信App是通过接口回调异步反馈的;支付宝App是通过函数返回值异步反馈的

微信主要通过后台对后台的方式传递订单和支付信息;支付宝则是主要通过App

(如果说支付行为好像是上楼签合同的话,在微信App支付里,你的后台是那个上楼送合同的人,你的App只是个按电梯开关的;在支付宝App支付,你的App是那个拿着合同上楼的人)

微信先通过后台完成支付,然后通知App;支付宝先通过App完成支付,然后后台跟进

微信支付成功会跳转Activity(要自己写);支付宝是纯逻辑处理

php语法分析

1,array_merge与 + 的区别

数字索引数组:+ 号取前一个的值,忽略后值,array_merge()后面的数组追加到前面数组的后面,合并后的数组重新排序

字符串索引数组:+ 号取前一个的值,忽略后值,array_merge()后面的相同key会取代前面的值

slim+nginx请求报 404

请求1  http://www.slim.com 正常

请求2 http://www.slim.com/users 报404

上面两个在路由文件已经配置了,为什么一个成功一个失败呢?

检查:发现请求2没有走到代码里面,感觉时服务器配置问题

网上查了一下时伪静态问题

nginx设置

root        /Users/jackluo/Works/php/rest;

    location / {
        root    /Users/jackluo/Works/php/rest;
        index   index.html index.php;
        try_files $uri $uri/ /index.php?$args;
    }

继续阅读“slim+nginx请求报 404”

http状态码

面试时被问到状态码201含义,没回答上来。

HTTP状态码分类

HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:

HTTP状态码分类
分类 分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

HTTP状态码列表:

HTTP状态码列表
状态码 状态码英文名称 中文描述
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建了新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求
300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经被废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

php表单重复提交解决办法

一:利用js设置按钮点击后变成灰色

点击完按钮之后变成灰色就不能点击了,用户需要再次提交表单的话就要刷新页面之后重新填写数据再提交了。

二:利用session

session中放一个特殊标志。当表单页面被请求时,生成一个特殊的字符标志串,存在session中,同时放在表单的隐藏域里。接受处理表单数据时,检查标识字串是否存在,并立即从session中删除它,然后正常处理数据。

如果发现表单提交里没有有效的标志串,这说明表单已经被提交过了,忽略这次提交。

这使你的web应用有了更高级的XSRF保护

加载提交的页面时候,生成一个随机数,

$code = mt_rand(0,1000000);

存储在表单的隐藏输入框中:

< input type=”hidden” name=”code” value=””>


三:利用cookies

原理和session差不多,但是cookies一旦用户浏览器禁用cookies,这功能就失效了

四:利用header函数跳转

一旦用户点击提交按钮,处理完数据后跳到其他页面

if (isset($_POST[‘submit'])) {
header(‘location:success.php');//处理数据后,转向到其他页面
}

五:利用数据库来添加约束

直接在数据库里添加唯一约束或创建唯一索引,一旦发现用户重复提交了,直接抛出警告或者提示,或者只处理第一次提交的数据,这是最直接有效的方法,要求前期的数据库设计和架构要考虑周全.

六:Post/Redirect/Get模式。

在提交后执行页面重定向,这就是所谓的Post-Redirect-Get (PRG)模式。简言之,当用户提交了表单后,你去执行一个客户端的重定向,转到提交成功信息页面。

if (isset($_POST[‘action']) && $_POST[‘action'] == ‘submitted') {
//处理数据,如插入数据后,立即转向到其他页面
header('location:submits_success.php');
}
七,使用redis setnx锁,防止并发重复提交

初步设想:

$lock_key = 'LOCK_PREFIX' . $redis_key;//根据业务自定义
$is_lock = $redis->setnx($lock_key, 1); // 加锁
if($is_lock == true){ // 获取锁权限
    $redis->setex($redis_key, $expire, $data); // 写入内容
    // 所有逻辑执行完毕释放锁
    $redis->del($lock_key);
}else{
    // 防止死锁
    if($redis->ttl($lock_key) == -1){//为-1表示没有设置过期时间
        $redis->expire($lock_key, 5);
    }
    return true; // 获取不到锁权限,直接返回
}

但上面的代码有问题:加锁 和 设置过期时间 是两个动作,整个加锁操作就不是一个原子性操作,有可能存在setnx加锁成功,但因程序异常退出导致未成功设置超时时间,在不及时解锁的情况下,有可能会导致死锁(即使业务场景中不会出现死锁,无用的key一直常驻内存也不是很好的设计)

把setnx与expire两条指令作为一个原子性操作执行,Redis 2.6.12之后版本Redis set指令支持了nx、ex模式,并支持原子化地设置过期时间

优化后的代码如下

$lock_key = 'LOCK_PREFIX' . $redis_key;//根据业务自定义
if ($is_lock == true) { // 获取锁权限
    $redis->set($lock_key, 1, ['nx', 'ex' => 1000]); // 加锁,设置过期时间一起完成,原子性操作
    // 所有逻辑执行完毕释放锁
    $redis->del($lock_key);
}

Elasticsearch ik分词器找不到对应dic文件

1.配置了IKAnalyzer.cfg.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">yang.dic;</entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords"></entry>
	<!--用户可以在这里配置远程扩展字典 -->
	<!-- <entry key="remote_ext_dict">words_location</entry> -->
	<!--用户可以在这里配置远程扩展停止词字典-->
	<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

2.在文件IKAnalyzer.cfg.xml同一级新建yang.dic自定义自定义字典文件
3.重启es报not found file yang.dic

继续阅读“Elasticsearch ik分词器找不到对应dic文件”

大鱼号发布文章审核未通过,我是怎么办的

大鱼号发布文章有严格的审核过程,一不小心就会审核不通过。辛辛苦苦的创作提交之后,不能发表,失落心情可想而知。而审核不通过的原因平台并没有具体指出,这就让很多作者苦恼。

我今天就遇到了,贴图为证:

尝试解决,

1,换标题,提交,审核未通过,不符合相关法律法规(不符合什么法规呢?不知道)

2,是不是图片敏感呢,好吧,调增图片顺序,提交,审核还是没有通过,不符合平台收录规则(具体啥规则我也不知道?)

3,难道是文章结尾的图片版权信息违规?删除,在提交,还是未通过(这可咋办呢?)

4,睡觉前觉得自己辛苦写的不能发表,太难过,再做修改。改标题,去除感觉不行的插图,凭感觉替换关键字,在提交,想骂人,审核通过了,我太难了。

好在成功了,不然真的要放弃了。既然是自己写的,自己就有信心通过审核,无非就是一些敏感图片和词句,自己凭感觉还是能找出并修改使之符合平台发文规范的。

nginx初探

nginx应用场景

静态处理

反向代理

负载均衡

资源缓存

安全防护

访问控制

访问认证

下载站点及用户权限认证配置
 1.下载站点配置
          location /down {
                root /usr/share/nginx;
                autoindex on;
                autoindex_localtime on;
                autoindex_exact_size off;
                #访问down目录开启权限认证
                auth_basic "请输入用户名和密码";
                auth_basic_user_file /etc/nginx/auth_conf;#此目录保存的是用户名和密码 
          }
2.
#yum install httpd_tools //安装工具
#htpasswd -b /etc/nginx/auth_conf test 123 //生成用户名为test 密码为123
3.当访问http://xxxxx/down时需要输入上面的用户名和密码

继续阅读“nginx初探”

mysql类型长度剖析int,char(索引explain里面的key_len计算)

int

mysql中int(1)和int(11)区别呢,按理来讲int定义之后长度不受我们设置的限制了,那么mysql中int(1)和int(11)区别是什么呢?

mysql字段定义中INT(x)中的x仅仅指的是显示宽度。该可选显示宽度规定用于显示宽度小于指定的列宽度的值时从左侧填满宽度(前提 zerofill选项必须选择才会填充)int(5)如果插入的是1,并且定义zerofill,这数据库显示为00001。显示宽度并不限制可以在列内保存的值的范围,也不限制超过列的指定宽度的值的显示。所以x的定义与存储空间没有任何关系都是4个字节

原文链接:https://blog.csdn.net/qq_34129814/java/article/details/80015434

char

char(x)和varchar(x),x代表可存储的长度,超过长度报错,这点和int不同

 

key_len计算

变长字段需要额外的2个字节,固定长度字段不需要额外的字节。而null都需要1个字节的额外空间,所以:索引字段最好不要为NULL,因为NULL让统计更加复杂,并且需要额外一个字节的存储空间。

key_len的长度计算公式:
int类型的是4,如果允许空则4+1 
varchr(10)变长字段且允许NULL      : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)
varchr(10)变长字段且不允许NULL    : 10*(Character Set:utf8=3,gbk=2,latin1=1)+2(变长字段)

char(10)固定字段且允许NULL        : 10*(Character Set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允许NULL        : 10*(Character Set:utf8=3,gbk=2,latin1=1)