8

So I have spent weeks researching how to get a pdf from the server via ajax and then show it to the client. The reason I need to do this is a user can't just go to the pdf directly on the server, because they won't provide a token to pass security, but with javascript I can. Using the following code I am able to get what I am expecting:

 var xhr = new XMLHttpRequest();
 xhr.open('GET', url, true);
 xhr.responseType = 'arraybuffer';
 xhr.setRequestHeader("token", token.value);
 xhr.onload = function (e) {
    if (this.status == 200) {
       var file = new Blob([this.response], { type: 'application/pdf' });
       var fileURL = URL.createObjectURL(file);
       window.open(fileURL, '_blank');
    }
 };
 xhr.send();

However when I try and do this exact thing in angular like this (I'm doing half of this stuff just so the headers match in both):

var config = {
    url: url,
    method: 'GET',
    responseType: 'arraybuffer',
    headers: {
        'Accept':'*/*',
        "token": token.value
    }
}

$http(config)
    .success(function (response) {
        var file = new Blob([response], { type: 'application/pdf' });
        var fileURL = URL.createObjectURL(file);
        window.open(fileURL, '_blank')
    });

Here is what the headers look like in both:

GET http://example.com HTTP/1.1
Host: example.com
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
token: test
Referer: http://example.com
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

The only difference is the xmlhttprequest version has Authorization: Negotiate header, but I can render both of them in fiddler from the responses from the server. This tells me that 'response' from $http isn't the same as this.response in xmlhttprequest. Can someone please tell me what is different and how I can fix it?

I thought for a long time that it was a charset problem and I have even base64 the bytes before sending it over the wire and then used atob() to switch it back, but that didn't seem to make it any better. It seems the $http version takes the response and converts the bytes to utf8 even if they aren't...my bytes are I think are windows-1252/latin1/ios-8895-1

The reason I say this is because I saw this in a hex editor:

btye 85 (on server) switched to two bytes of C2 85 (after $http code) http://www.fileformat.info/info/unicode/char/85/charset_support.htm

btye c5 (on server) switched to two bytes of c3 85 (after $http code) http://www.fileformat.info/info/unicode/char/c5/charset_support.htm

I have even tried to encode/decode if various combinations with no avail. I really think the pdf is getting corrupted some how when it's going through angular, but I don't know how.

UPDATE 1

On the server side the code looks like this:

public class LabelController : Controller
{
  //using Microsoft.AspNet.Mvc
  [HttpGet, Route("api/labels/box")]
  public IActionResult BoxLabels(Guid requestId)
  {
    var data = this.getPDF("http://foobar.com/example.pdf");
    Response.Headers.Add("Content-Length", data.Length.ToString());
    Response.Headers.Add("Content-Disposition", "inline; filename=example.pdf");
    return new FileContentResult(data, "application/pdf");
  }

  //using restsharp
  private bytes[] getPDF(url)
  {
    var client = new RestClient
    {
      BaseUrl = new Uri(url),
      Authenticator = new NtlmAuthenticator()
    };

    var request = new RestRequest
    {
      Method = Method.POST,
      Credentials = CredentialCache.DefaultNetworkCredentials,
      RequestFormat = DataFormat.Xml
    };

    var response = client.Execute(request);
    return response.RawBytes;
  }
}

Here is sort of what it looks like: http://plnkr.co/edit/R3FiesPk7Os22SMsTTfE without the "No 'Access-Control-Allow-Origin'" error

UPDATE 2

Here is what the network traffic tells me: inspection of ajax call

Here is what the pdf looks like when using $http:

blank pdf when using $http

7
  • can you show the angular html and the directive? Do you have a punker set up that you can share? What are your result exactly? Commented May 11, 2016 at 17:11
  • If I show the angular html and directive this would get much longer and I'm not sure it adds any value to the question. I'll add what I did on the c# part though Commented May 11, 2016 at 17:23
  • Can you create a plunker to help understand your issue. Here is a link to mine. This shows rendering PDF's in angular. plnkr.co/edit/gFfGQCzAfmf2zf5C2Bpc?p=preview Commented May 11, 2016 at 17:38
  • Not sure this helps as I'm getting a cross-origin error which I do not have in my version because they are on the same domain and I have security on the server. plnkr.co/edit/R3FiesPk7Os22SMsTTfE Commented May 11, 2016 at 18:54
  • is it turning your request into an "Option"? Commented May 11, 2016 at 19:02

2 Answers 2

1

So I think your issue is that the browser is doing a CORS Preflight because you are doing a cross browser request. It is turning a GET request into an OPTIONS.

enter image description here

You will need to add the OPTIONS request to your accepted CORS Options. You may also need to add your IP address to the accepted Origins within the CORS Options.

Here are some helpful links for this: http://barnabas.tumblr.com/post/87914971548/the-curse-of-the-cors-preflight-and-how-to-defeat Confused about how to handle CORS OPTIONS preflight requests

Sign up to request clarification or add additional context in comments.

2 Comments

The plunker example I gave has cross side scriptting problems because I couldn't upload a pdf to plunker, but mine is on the same domain nor find a pdf that has access-control-allow-origin on...it is somehting like example.com/ (ui) and example.com/api (service), however I will double check to make sure.
Nope it is a get method. I added it to my question.
0

I'm trying to learn Angular, and thought it would be interesting to see if this really is an Angular mangling problem. So I created a simple node webserver and used exactly your code.

I can show a PDF in a browser window using the Angular code you say is failing for you. The only gotcha is that your approach doesn't work in Microsoft's Edge because blob URLs aren't supported for security reasons.

The code is on GitHub and an earlier version is on C9.

I then wondered if this was an IIS/restsharp/ASP.NET MVC problem. However I pretty quickly created an ASP.NET MVC application using restsharp that also works with Angular, using code very similar to yours. This is also on GitHub. Your restsharp code needed a little love, but again it all worked fine first time for me.

So the reason you're not getting any answers here is that I don't think there's enough information in the question to figure out what's wrong in your environment. I hope this stuff is helpful though.

1 Comment

It looks like you've created most of my problem, but you didn't add in the security part of the asp, which i'm starting think might be the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.