
# 如何通过华为云Astro轻应用脚本，导出xls文件让用户下载？
#### 问题描述
华为云Astro轻应用提供了"excel"脚本标准库，用于操作Excel文件，例如生成Excel文件。由于华为云Astro轻应用脚本编排的标准输出格式是JSON，因此这里需要做一些特殊处理，让系统生成非JSON数据才能实现xlsx文件导出。
#### 操作步骤
1. 参考[开发一个简单脚本实例](https://support.huaweicloud.com/usermanual-astrozero/astrozero_05_9162.html)中操作，创建一个名称为"cube__download"的空白脚本。
2. 在脚本编辑器中，输入如下脚本代码。 
   ```
   import * as excel from 'excel';
   import * as context from 'context';
   import * as buffer from 'buffer';
   export class Download {
       @action.method({ input: "Input", output: "Output", description: "do a operation" })
       run(): void {
           // 原始数据，可以从数据表中获取，此处为了演示方便，使用静态数据
           let binary = excel.encode(['a', 'b', 'c'], [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }, { 'a': 7, 'b': 2, 'c': 3 }]);
           // 对于 Excel2007 以上版本的 .xlsx 文件，需要设置内容类型为 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
           context.getHttp().response.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64');
           // 直接把二进制作为请求体返回       
    context.getHttp().response.setBody(buffer.fromBytes(binary).toString(buffer.Encoding.Base64));
       }
   }
   ```
   此时，后端返回了一个base64编码的二进制数据，并非JSON格式，所以直接运行脚本不会有输出，需要在前端页面匹配处理这种数据才行。
   
   
3. 在标准页面上，调用"cube__download"脚本。 
   为了简化配置，此处没有把脚本封装为公共接口，实际使用时业务应该使用公共接口进行封装，以便实现更细粒度的权限控制。
   以jQuery的ajax方法为例，代码示例如下：
   ```
   var url = "/u-route/baas/script/v1.0/run/cube__download";
   context.$utils.getCSRFToken().then(function(token) {
       $.ajax({
           type: "POST",
           headers: {
               'Content-Type': "application/json",
               'responseType':"arraybuffer",
               'csrf-token': token,
           },
           url: url,
           data: JSON.stringify({}),
           dataType: 'text',
           async: false,
           success: function(resp){
               var fileName = "test" + '.xlsx';
               var file = new Blob([s2ab(atob(resp))], {type: ''});
               if (window.navigator.msSaveOrOpenBlob) { //IE浏览器下载
                   window.navigator.msSaveOrOpenBlob(file, fileName);
               } else {  
                   var fileUrl = URL.createObjectURL(file);
                   var a = document.createElement('a');
                   a.href = fileUrl;
                   a.target = '_blank';
                   a.download = fileName;
                   document.body.appendChild(a);
                   a.click();
               }
           },
           error: function(resp){
           }
       });
   });
   ```
   "s2ab()"是数据处理的关键，这个方法名字是"string to array buffer"的缩写，意思是把字符串转换为ArrayBuffer类型，以便让前端可以处理二进制数据。其函数定义如下：
   ```
   function s2ab(s) {
       var buf = new ArrayBuffer(s.length);
       var view = new Uint8Array(buf);
       for (var i=0; i!=s.length; ++i) {
           view[i] = s.charCodeAt(i) & 0xFF;
       }
       return buf;
   }
   ```
   上述代码中，需要注意如下事项：
   - Header里面需要增加'responseType':"arraybuffer"；
   
   - Header里的类型为dataType: 'text'；
   
   - Header里增加csrf-token。
   
   
   
   
 
