http://techmikael.blogspot.in/2013/07/how-to-copy-files-between-sites-using.html

I’m currently playing with a POC for an App, and wanted to try to do the App as a SharePoint hosted one, only using JavaScript and REST.
The starting point was to call _vti_bin/ExcelRest.asmx on the host web from my app web, but this end-point does neither support CORS nor JSONP, so it can’t be used directly. My next thought was; Ok, let’s copy the file from the host web over to my app web, then call ExcelRest locally. Easier said than done!
While the final solution seems easy enough, the research, trial and error have taken me about 3 days. I’m now sharing this with you so you can spend your valuable time increasing the international GDP instead.
Note: If you want to copy files between two libraries on the same level, then you can use the copyTo method. http://server/site/_api/web/folders/GetByUrl('/site/srclib')/Files/getbyurl('madcow.xlsx')/copyTo(strNewUrl = '/site/targetlib/madcow.xlsx,bOverWrite = true)

Problem

Copy a file from a document library in one site to a document library in a different site using JavaScript and REST.
The code samples have URL’s using the App web proxy, but it’s easily modifiable for non-app work as well.

Step 1 – Reading the file

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

var hostweburl = decodeURIComponent(getParameterByName('SPHostUrl'));

var appweburl = decodeURIComponent(getParameterByName('SPAppWebUrl'));

var fileContentUrl = "_api/SP.AppContextSite(@target)/web/GetFileByServerRelativeUrl('/site/library/madcow.xlsx')/$value?@target='" + hostweburl + "'";

var executor = new SP.RequestExecutor(appweburl);

var info = {

url: fileContentUrl,

method: "GET",

binaryStringResponseBody: true,

success: function (data) {

//binary data available in data.body

var result = data.body;

},

error: function (err) {

alert(JSON.stringify(err));

}

};

executor.executeAsync(info);

The important parameter here is setting binaryStringResponseBody to true. Without this parameter the response is being decoded as UTF-8 and the result in the success callback is garbled data, which leads to a corrupt file on save.
The  binaryStringResponseBody parameter is not documented anywhere, but I stumbled upon binaryStringRequestbody in an msdn article which was used when uploading a file, and I figured it was worth a shot. Opening SP.RequestExecutor.debug.js I indeed found this parameter.

Step 2 – Patching SP.RequestExecutor.debug.js

Adding binaryStringResponseBody will upon return of the call cause a script error as seen in the figure below.

The method in question is reading over the response byte-by-byte from an Uint8Array, building a correctly encoded string. The issue is that it tries to concatenate to a variable named ret, which is not defined. The defined variable is named $v_0, and here we have a real bug in the script. The bug is there both in Office365 and SharePoint 2013 on-premise.
Luckily for us patching JavaScript is super easy. You merely override the methods involved somewhere in your own code before it’s being called. In the below sample it’s being called once the SP.RequestExecutor.js library has been loaded. The method named BinaryDecode is the one with the error, but you have to override more methods as the originator called is internalProcessXMLHttpRequestOnreadystatechange, and it cascades to calling other internal functions which can be renamed at random as the method names are autogenerated. (This happened for me today and I had to change just overrinding the first function).

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

$.getScript(scriptbase + "SP.RequestExecutor.js", function(){

SP.RequestExecutorInternalSharedUtility.BinaryDecode = function SP_RequestExecutorInternalSharedUtility$BinaryDecode(data) {

var ret = '';

if (data) {

var byteArray = new Uint8Array(data);

for (var i = 0; i < data.byteLength; i++) {

ret = ret + String.fromCharCode(byteArray[i]);

}

}

;

return ret;

};

SP.RequestExecutorUtility.IsDefined = function SP_RequestExecutorUtility$$1(data) {

var nullValue = null;

return data === nullValue || typeof data === 'undefined' || !data.length;

};

SP.RequestExecutor.ParseHeaders = function SP_RequestExecutor$ParseHeaders(headers) {

if (SP.RequestExecutorUtility.IsDefined(headers)) {

return null;

}

var result = {};

var reSplit = new RegExp('\r?\n');

var headerArray = headers.split(reSplit);

for (var i = 0; i < headerArray.length; i++) {

var currentHeader = headerArray[i];

if (!SP.RequestExecutorUtility.IsDefined(currentHeader)) {

var splitPos = currentHeader.indexOf(':');

if (splitPos > 0) {

var key = currentHeader.substr(0, splitPos);

var value = currentHeader.substr(splitPos + 1);

key = SP.RequestExecutorNative.trim(key);

value = SP.RequestExecutorNative.trim(value);

result[key.toUpperCase()] = value;

}

}

}

return result;

};

SP.RequestExecutor.internalProcessXMLHttpRequestOnreadystatechange = function SP_RequestExecutor$internalProcessXMLHttpRequestOnreadystatechange(xhr, requestInfo, timeoutId) {

if (xhr.readyState === 4) {

if (timeoutId) {

window.clearTimeout(timeoutId);

}

xhr.onreadystatechange = SP.RequestExecutorNative.emptyCallback;

var responseInfo = new SP.ResponseInfo();

responseInfo.state = requestInfo.state;

responseInfo.responseAvailable = true;

if (requestInfo.binaryStringResponseBody) {

responseInfo.body = SP.RequestExecutorInternalSharedUtility.BinaryDecode(xhr.response);

}

else {

responseInfo.body = xhr.responseText;

}

responseInfo.statusCode = xhr.status;

responseInfo.statusText = xhr.statusText;

responseInfo.contentType = xhr.getResponseHeader('content-type');

responseInfo.allResponseHeaders = xhr.getAllResponseHeaders();

responseInfo.headers = SP.RequestExecutor.ParseHeaders(responseInfo.allResponseHeaders);

if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 1223) {

if (requestInfo.success) {

requestInfo.success(responseInfo);

}

}

else {

var error = SP.RequestExecutorErrors.httpError;

var statusText = xhr.statusText;

if (requestInfo.error) {

requestInfo.error(responseInfo, error, statusText);

}

}

}

};

});

Step 3 – Uploading the file

The next step is to save the file in a library on my app web. The crucial part again is to make sure the data is being treated as binary, this time withbinaryStringRequestBody set to true. Make a note of the digest variable as well. On a page inheriting the SP masterpage you can get this value with $("#__REQUESTDIGEST").val(). If not then you have to execute a separate call to _api/contextinfo. The code for that is at the bottom of this post.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

var appweburl = decodeURIComponent(getParameterByName('SPAppWebUrl'));

var executor = new SP.RequestExecutor(appweburl);

var info = {

url: "_api/web/GetFolderByServerRelativeUrl('/appWebtargetFolder')/Files/Add(url='madcow.xlsx', overwrite=true)",

method: "POST",

headers: {

"Accept": "application/json; odata=verbose",

"X-RequestDigest": digest

},

contentType: "application/json;odata=verbose",

binaryStringRequestBody: true,

body: arrayBuffer,

success: function(data) {

alert("Success! Your file was uploaded to SharePoint.");

},

error: function (err) {

alert("Oooooops... it looks like something went wrong uploading your file.");

}

};

executor.executeAsync(info);

Journey

I started out using jQuery.ajax for my REST calls, but I did not manage to get the encoding right no matter how many posts I read on this. I read through a lot on the following links which led me to the final solution:

Get the digest value

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

$.ajax({

url: "_api/contextinfo",

type: "POST",

contentType: "application/x-www-url-encoded",

dataType: "json",

headers: {

"Accept": "application/json; odata=verbose",

},

success: function (data) {

if (data.d) {

var digest = data.d.GetContextWebInformation.FormDigestValue;

}

},

error: function (err) {

alert(JSON.stringify(err));

}

});

How to copy files between sites using JavaScript REST in Office365 / SharePoint 2013的更多相关文章

  1. 关于在SharePoint 2013(2010)中Javascript如何实现批量批准的自定义操作功能?

    1.概述: SharePoint 2013(包括SharePoint 2010)提供了很方便的,多选的界面,但是很多操作还是不能批量进行,比如:批准的功能.如果您要解决方案不关心代码,那么请直接联系作 ...

  2. Xcode6 ADD Copy Files Build Phase 是灰色的

    在学习的怎样写frameWork的时候,查看一个教程How to Create a Framework for iOS  [一个中文翻译 创建自己的framework] 其中一个步骤就是添加一个Cop ...

  3. How do I copy files that need root access with scp

    server - How do I copy files that need root access with scp? - Ask Ubuntuhttps://askubuntu.com/quest ...

  4. Gradle Goodness: Copy Files with Filtering

    Gradle Goodness: Copy Files with Filtering Gradle's copy task is very powerful and includes filterin ...

  5. [MSDN] 使用 SharePoint 2013 中的 JavaScript 库代码完成基本操作

    MSDN:http://msdn.microsoft.com/zh-cn/library/jj163201.aspx 了解如何编写代码以在 SharePoint 2013 中使用 JavaScript ...

  6. SharePoint 2013 中使用 JavaScript Like 和Unlike list item/page/document

    SharePoint 2013中新增了很多社交功能,比如用户可以like/unlike 任何一个 list item/page/document,这是一个非常不错的功能. 但有时觉得like/unli ...

  7. [Forward]Visual Guide: Setting up My Sites in SharePoint 2013

    from  http://blog.sharedove.com/adisjugo/index.php/2012/07/25/visual-guide-setting-up-my-sites-in-sh ...

  8. [Bash] Move and Copy Files and Folders with Bash

    In this lesson we’ll learn how to move and rename files (mv) and copy (cp) them. Move index.html to ...

  9. VS Copy Files after build

    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ItemGroup> ...

随机推荐

  1. 【转】每个人应该知道的NVelocity用法

    NVelocity是一个基于.NET的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由.NET代码定义的对象.从而使得界面设 ...

  2. NoSql---MongoDB基本操作

    MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语 言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引.最后由于 MongoDB 可以支 ...

  3. Ext.js中的tip事件实际使用

    Ext.onReady(function () { // Init the singleton. Any tag-based quick tips will start working. Ext.ti ...

  4. 用C#实现修改网页数据

    背景    由于某宝最近升级,导致朋友买的刷单软件不能用了:在又付过钱之后,那个刷单软件供应商竟然捐款跑路了...于是,朋友委托我做一个功能一样的软件.功能    他给我描述的软件功能,是这个样子的: ...

  5. ArcGIS平台中PostgreSQL数据连接配置总结

    通常用户在使用要素服务时,要求数据必须是存放在空间数据库中的.同时,需要将数据库注册到ArcGIS for Server,这样在发布服务时就不需要进行数据拷贝,从而可以节省磁盘空间及服务发布时间.以下 ...

  6. PowerMock 简介--转载

    原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-powermock/ EasyMock 以及 Mockito 都因为可以极大地简化单元测试的书 ...

  7. JS设计模式1-单例模式

    单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如全局缓存,window对象.单例模式在js开发中单例模式的用途非常广泛,比如页面中有一个登录浮窗,无论单击多少次登录窗口,这个窗口只会创建一 ...

  8. Vue基础---->VueJS的使用(一)

    Vue.js是一个构建数据驱动的web界面的库.它的目标是通过尽可能简单的API 实现响应的数据绑定和组合的视图组件,今天我们就开始vue.js的学习. vue的安装及使用 一.vue的下载地址:ht ...

  9. suricata学习笔记1--初步认识

    1.前言  最近工作需要对网站的关键字进行检测,找出敏感词.这个过程需要对报文进行收集.解码.检测和记录日志.当前只是简单实现功能,根据关键字进行简单的匹配,而没有进行关键字的语义分析.导致的结果就是 ...

  10. The Top 10 Javascript MVC Frameworks Reviewed

    Over the last several months I have been in a constant search for the perfect javascript MVC framewo ...