答卷提交后跳转推送
<p>[TOC]</p>
<h1>一、接口功能应用场景</h1>
<p>在问卷设置》跳转设置》跳转到指定页面设置跳转目标的URL,并且开启“POST答卷数据到该地址”的功能。就可以实现:填写者在提交答卷后,跳转到这个指定的<code>URL</code>页面,并且系统会同步将该填写者作答的数据<code>POST</code>到该<code>URL</code>页面。</p>
<p>应用场景:在填写者提交答卷后,可以跳转到用户自己的系统页面,并且作答信息(通过接口获取到的)作为页面元素显示在自己系统页面。如:考试问卷如果不想使用问卷星提供的标准成绩单,可以使用该功能,自己写一个成绩单页面作为跳转页面。</p>
<h1>二、页面目标地址</h1>
<p>使用页面目标地址需要注意以下问题:</p>
<p>1、该地址需保证外网可访问的状态;</p>
<p>2、该地址需要承载填写者提交答卷后的跳转落地页,所以需保证合适的页面内容;</p>
<p>3、数据将以表单的方式<code>POST</code>到该地址,需要增加开发代码以读取<code>form</code>表单数据的<code>content</code>内容。</p>
<h1>三、POST答卷数据</h1>
<p>POST答卷数据会将每个填写者作答的数据,在其点击“提交”时推送到“页面目标地址”。每个填写者点击提交,就会执行一次推送操作;</p>
<h2>1、推送机制</h2>
<p>1) 用户在问卷设置界面设置跳转到指定页面,并勾选“POST答卷数据到该地址”;
<img src="https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/0ea85d6913438e43fa79fcf49e3941c9" alt="" />
2) 如果需要获取问卷内容,可同时勾选“POST问卷内容到该地址”。如果未显示此选项,请联系客服顾问开通权限;</p>
<p>3) <code>POST</code>答卷数据到跳转的指定页面的方式,与数据推送<code>API</code>方式只能二选一,推荐使用<code>POST</code>答卷数据到跳转的指定页面;这种方式的实时效性、稳定性更强;</p>
<p>用户在提交完答卷后,问卷星将直接跳转到指定的页面并将答卷数据放在<code>POST</code>消息体中;</p>
<p>跳转到用户指定页面后,用户指定页面可以同时读取到<code>GET</code>和<code>POST</code>的内容;</p>
<h2>2、数据加密</h2>
<p>考虑到答卷数据传输的安全性,推送的答卷数据进行了<code>AES</code>加密,加密密钥可以在设置界面获取到;</p>
<p>解密方法如下:</p>
<pre><code class="language-csharp">1)读取推送的BASE64数据为byte[] encryptedData;
2)取AES加解密密钥作为AES解密的KEY
3) 取byte[] encryptedData的前16位做为IV;
4)取第16位后的字节数组做为待解密内容;
5)解密模式使用CBC(密码块链模式);
6)填充模式使用PKCS #7(填充字符串由一个字节序列组成,每个字节填充该字节序列的长度);
7)使用配置好的实例化AES对象执行解密;
8)使用UTF-8的方式,读取二进制数组得到原始数据</code></pre>
<p>示例代码(C#)</p>
<pre><code class="language-csharp">//1)读取推送的BASE64数据为byte[] encryptedData;
byte[] encryptedData = Convert.FromBase64String(encrypted);
if (encryptedData == null || encryptedData.Length < 17)
return null;
//2)取AES加解密密钥作为AES解密的KEY;
byte[] key = Encoding.UTF8.GetBytes(aesKey);
//3) 取byte[] encryptedData的前16位做为IV;
byte[] iv = encryptedData.Take(16).ToArray();
//4)取第16位后的字节数组做为待解密内容;
encryptedData = encryptedData.Skip(16).ToArray();
using (var aes = new RijndaelManaged())
{
//5)解密模式使用CBC(密码块链模式);
aes.Mode = CipherMode.CBC;
//6)填充模式使用PKCS #7(填充字符串由一个字节序列组成,每个字节填充该字节序列的长度);
aes.Padding = PaddingMode.PKCS7;
aes.Key = key;
aes.IV = iv;
var cryptoTransform = aes.CreateDecryptor();
//7)使用配置好的实例化AES对象执行解密
byte[] r = cryptoTransform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
//8)使用UTF-8的方式,读取二进制数组得到原始数据
return Encoding.UTF8.GetString(r);
}</code></pre>
<p>示例代码(java)</p>
<pre><code class="language-java">import sun.misc.BASE64Decoder;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AesUtils {
private static String ALGO = "AES";
private static String ALGO_MODE = "AES/CBC/NoPadding";
public static String aesDecrypt(String encryptedData, String securityKey) {
try {
byte[] data = (new BASE64Decoder()).decodeBuffer(encryptedData);
byte[] iv = Arrays.copyOfRange(data, 0, 16);
Cipher cipher = Cipher.getInstance(ALGO_MODE);
SecretKeySpec keySpec = new SecretKeySpec(securityKey.getBytes("utf-8"), ALGO);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] countent = Arrays.copyOfRange(data, 16, data.length);
byte[] original = cipher.doFinal(countent);
String originalString = new String(original);
return originalString.trim();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
</code></pre>
<h2>3、推送内容及格式</h2>
<p>1、推送内容存储在表单(<code>application/x-www-form-urlencoded</code>)的<code>content</code>字段中;
2、<code>content</code>字段的值为经过<code>aes</code>加密后的<code>base64</code>字符串,解密后的内容包括答卷数据以及问卷数据;
3、答卷数据:推送内容及格式与数据推送<code>API</code>相同,参见:<code>https://www.wjx.cn/help/help.aspx?helpid=407&h=1</code></p>
<p>4、问卷数据:推送内容及格式与问卷开放<a href="https://www.showdoc.com.cn/wjxopenapi/7556919558404006" title="API[1000001]">API[1000001]</a>接口相同;</p>
<h1>DEMO</h1>
<h2>1、demo地址:</h2>
<p><code>https://www.wjx.cn/demo/activityredirect.aspx?aes=822861f9c5114dc2bda214cd9567d0dc</code>注:aes=为AES解密密钥</p>
<h2>2、示例代码(C#):</h2>
<pre><code class="language-csharp">public partial class demo_activityredirect : System.Web.UI.Page
{
string aeskey = "";
string content = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
content = Request.Form["content"];
aeskey = Request.QueryString["aes"];
Response.Write("推送的加密内容[content]:" + Receive());
Response.End();
}
//接收推送消息
protected string Receive()
{
try
{
if (!string.IsNullOrEmpty(content) && !string.IsNullOrEmpty(aeskey))
{
content = Wjx.Common.Encrypt.Aes.Decrypt(content, aeskey);
return content;
}
return "读取内容为空";
}
catch (Exception e)
{
return "出错啦!\r\n" + e.Message;
}
}
}</code></pre>