阿里云，AWS，HTTPS和企业支付宝配置
# 申请证书

- 登录：阿里云控制台，产品与服务，证书服务，购买证书。
- 购买：证书类型选择 免费型DV SSL，然后完成购买。

要来回点击寻找一下，因为免费版隐藏了

![image](https://user-images.githubusercontent.com/17243165/38716964-559f0ab2-3f16-11e8-9ced-10ab483be7bc.png)

# 配置

等待阿里云签发成功，然后在右边栏目里面选择下载


![这里写图片描述](http://img.blog.csdn.net/20180417101922880?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjcwODAyNDc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

# 安装证书

文件说明：

1. 证书文件1523928142501.pem，包含两段内容，请不要删除任何一段内容。
2. 如果是证书系统创建的CSR，还包含：证书私钥文件1523928142501.key、证书公钥文件public.pem、证书链文件chain.pem。
( 1 ) 在Apache的安装目录下创建cert目录，并且将下载的全部文件拷贝到cert目录中。如果申请证书时是自己创建的CSR文件，请将对应的私钥文件放到cert目录下并且命名为1523928142501.key；
( 2 ) 打开 apache 安装目录下 conf 目录中的 `httpd.conf` 文件，找到以下内容并去掉“#”：
```bash
#LoadModule ssl_module modules/mod_ssl.so (如果找不到请确认是否编译过 openssl 插件)
#Include conf/extra/httpd-ssl.conf
```
( 3 ) 打开 apache 安装目录下 `conf/extra/httpd-ssl.conf` 文件 (也可能是conf.d/ssl.conf，与操作系统及安装方式有关)， 在配置文件中查找以下配置语句:

```bash
# 添加 SSL 协议支持协议，去掉不安全的协议
SSLProtocol all -SSLv2 -SSLv3
# 修改加密套件如下
SSLCipherSuite HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM
SSLHonorCipherOrder on
# 证书公钥配置
SSLCertificateFile cert/public.pem
# 证书私钥配置
SSLCertificateKeyFile cert/1523928142501.key
# 证书链配置，如果该属性开头有 '#'字符，请删除掉
SSLCertificateChainFile cert/chain.pem
```

( 4 ) 重启 Apache。
( 5 ) 通过 https 方式访问您的站点,测试站点证书的安装配置，如遇到证书不信任问题

> 这里注意如果使用阿里云还要在安全组规则里面设置443端口的出入方向

# Apache反向代理设置https

因为我是用express框架写的后端，apache默认占了80端口，express可以通过反向代理来享用80端口

首先在 **httpd.conf** 启用必要的模块，也就是如果去掉下面这几行前面的 `#`

```xml
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Include conf/extra/httpd-ssl.conf
```

在 **httpd.conf** 末端添加如下设置，注意 `ProxyPass` 和 `ProxyPassReverse` 设置为express框架暴露的端口，并且设置好 `SSLCertificateFile` 和 `SSLCertificateKeyFile` 的路径，路径就是上面安装证书步骤里面的路径
```xml
<VirtualHost *:80>
	ServerAdmin www.smms.ink
	ServerName www.smms.ink
	ProxyRequests Off
	<Proxy *>
	Order deny,allow
	Allow from all
	</Proxy>
	ProxyPass / http://127.0.0.1:1314/
	ProxyPassReverse / http://127.0.0.1:1314/
</VirtualHost>

<virtualhost *:443>
	ServerName www.smms.ink
	<proxy>
	Order deny,allow
	Allow from all
	</proxy>
	SSLEngine On
	SSLProxyEngine On
	SSLProxyVerify none
	SSLProxyCheckPeerCN off
	SSLProxyCheckPeerName off
	SSLCertificateFile cert/public.pem
	SSLCertificateKeyFile cert/1523928142501.key
	 
	ProxyRequests Off
	ProxyPreserveHost On
	 
	ProxyPass / http://127.0.0.1:1314/
	ProxyPassReverse / http://127.0.0.1:1314/
</virtualhost>
```

此时当我们访问 `https://www.xxx.com` 就等于 访问到内网的 `http://127.0.0.1:1314`
这样对 `https://www.xxx.com` 的访问，返回的数据将是来自 `http://127.0.0.1:1314`

上面的这个配置思路总结为如下三步：

1. 正常启动express项目在1314端口 
2. 然后用apache服务器实现反向代理 
3. 再用apache配置https

# Apache和node共享端口

参考文档[Apache和nodejs公用80端口的问题](https://segmentfault.com/q/1010000000702092)

思路是通过不同域名来区分进去是apache解析还是node解析文件，可以利用二级域名来划分
```xml
ProxyPass / http://127.0.0.1:9000/
ProxyPassReverse / http://127.0.0.1:9000/
/ 映射到  http://127.0.0.1:9000/
```
你可以根据自己的路由规则来实现不用的需求，例如：

```xml
ProxyPass / http://127.0.0.1:9000/
ProxyPassReverse / http://127.0.0.1:9000/

ProxyPass /nodejs http://127.0.0.1:1314
ProxyPassReverse /nodejs http://127.0.0.1:1314
```

此时我们可以根据不同的二级路由进入内网的不同端口，拨入我们可以把/nodejs分配给node开的1314端口，那么外网就可以通过https://xxx/nodejs/xxx进入到nodejs的服务器中，对应如果是其他路由就会进入到apache服务器中


# 企业支付宝接入

接入之前建议先看[官方文档](https://docs.open.alipay.com/204/105297/)比较详细

## 创建应用

首先有企业支付宝账号，登录企业支付宝管理中心，登录不知道是不是安全校验太频繁，官网输入登录的时候特别卡特别慢，进入开发者中心，因为我选择的是网页&移动应用，要提供网址通过审核，审核通过就会出现下面的已上线应用

![image](https://user-images.githubusercontent.com/17243165/39089534-ce000268-45fb-11e8-8a2c-b76972bfd55e.png)

## 配置RSA密钥

下载官网中的[RSA签名验签工具](https://docs.open.alipay.com/291/105971)配置RSA2密钥，会生成**应用公钥**和**应用密钥**，注意上面选择中有**JAVA适用**和**非JAVA适用**的选项，因为我后端选择PHP所以我选择了**非JAVA适用**的PKCS1

![image](https://user-images.githubusercontent.com/17243165/39089579-46ed64a8-45fd-11e8-9e12-cbf680e1021f.png)

把**应用公钥**上传应用信息中的开发配置中，还有开发配置中的应用网关不是必填项，可以选择不填，然后将旁边的**支付宝密钥**复制到后端的SDK中的config.php中alipay_public_key字段后，注意**应用公钥**是跟**支付宝密钥**完全不同的，不要弄错，不然一会儿验签会失败

![image](https://user-images.githubusercontent.com/17243165/39089606-006b88ec-45fe-11e8-9d0d-3f03364a90a8.png)

## 配置服务器

下载对应的SDK文件[手机网站支付DEMO](https://docs.open.alipay.com/54/106682/)，这里根据对应的需求进行下载，有对应不同后端语言的，我下载的手机网站支付是有包含完整前后端的逻辑的DEMO

一般来说最简单的测试只需要配置config.php文件就可以了

```php
<?php
$config = array (	
	//应用ID,您的APPID。
	'app_id' => "xxxx",

	//商户私钥，您的原始格式RSA私钥，也就是应用私钥
	'merchant_private_key' => "xxxx",
		
	//异步通知地址
	//这里最好用http 支付宝的异步的回调在免费https证书下会失败
	'notify_url' => "http://工程公网访问地址/alipay.trade.wap.pay-PHP-UTF-8/notify_url.php",
		
	//同步跳转
	//'return_url' => "http://mitsein.com/alipay.trade.wap.pay-PHP-UTF-8/return_url.php",
		
	//编码格式
	'charset' => "UTF-8",

	//签名方式
	'sign_type'=>"RSA2",

	//支付宝网关
	'gatewayUrl' => "https://openapi.alipay.com/gateway.do",

	//支付宝公钥,查看地址：https://openhome.alipay.com/platform/keyManage.htm
        //对应APPID下的支付宝公钥。注意是支付宝公钥，而不是应用公钥，支付宝公钥是基于上传的应用公钥生成的
	'alipay_public_key' => "xxxx",
);
```
这里注意两点支付宝公钥和应用公钥，不要粘贴错，这里需要的是支付宝公钥而不是应用公钥，还有点就是notify_url和return_url

`return_url`是支付成功后在客户端返回给客户看的回调地址，需要和开发配置中的授权回调地址对应，这是支付宝对支付的一种校验，这个地址建议不要写任何支付后的操作逻辑，因为用户有可能会在客户端切掉看不到而影响逻辑判断

![image](https://user-images.githubusercontent.com/17243165/39089730-711ad60e-4600-11e8-98a3-0b68aedfd758.png)

`notify_url`是支付成功后支付宝通知给服务端的回调地址，这个地址注意要在公网可访问，因为支付宝会响应它，所以在本地测试中是不行的，必须上传到公网服务器，还有这里注意的是使用阿里云的免费https证书时候，这里如果地址是https会有一定失败率的，也就是说这里如果用了阿里云的免费https证书最好还是用回http地址响应，如果响应成功会echo出success这7个字符给支付宝，说明验签成功了，所以这个文件不要包含任何html代码，会影响结果输出，我们可以把支付后后端需要执行的逻辑放在这里，比如记录支付成功等

# 完整的交易逻辑

最重要就是 `WIDout_trade_no` 商品订单号，自己定义的，当我们发送支付到自己后端时候记录这个订单号，等支付宝验签回来成功后，对比信息中的订单号完成一个完整的支付逻辑，还要注意的是支付宝应该是只能用form表单提交支付请求，因为返回来的是一个form的代码，当然你也可以动态创建form来发送支付请求，但我个人建议还是直接静态form的形式来得方便


# APP和网页支付

注意APP和网页都要各自通过`签约`才可以调用支付接口的，之前在这里浪费了很久时间一直测试都是报`ALIN10146`错误就是因为忘记还没有APP签约

<img width="975" alt="2018-11-23 11 17 41" src="https://user-images.githubusercontent.com/17243165/48927537-8d5d8900-ef11-11e8-9b3c-3b12844c34e5.png">

APP内支付要真机连接查看返回的参数，注意后台PHP返回给APP的签名是不需要`htmlspecialchars`，不然这里会帮你把`&`转`&amp`，这里正确是`&`，不然APP支付会报`ALIN10146`
```php
// 注意：这里不需要使用htmlspecialchars进行转义，直接返回即可
echo $response;
//echo htmlspecialchars($response);//就是orderString 可以直接给客户端请求，无需再做处理。
```