Albertay
Albertay

Reputation: 53

How to read the JSON response content from a XMLHttpRequest?

Note: I'm using the CefSharp browser for this.

Goal

I'm trying to read every JSON response from a XMLHttpRequest.

What I've tried

public class RequestHandler : IRequestHandler
{
    public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        IResponse response, UrlRequestStatus status, long receivedContentLength)
    {
        if (request.Headers["X-Requested-With"] == "XMLHttpRequest" &&
            response.ResponseHeaders["Content-Type"] == "application/json")
        {
            var resourceHandler = new ResourceHandler();
            long responseLength;
            string redirectUrl;
            var stream = resourceHandler.GetResponse(response, out responseLength, out redirectUrl);
            using (var streamReader = new StreamReader(stream))
            {
                var responseContent = streamReader.ReadToEnd();
                Console.WriteLine(responseContent);
            }
        }
    }

    public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame,
        IRequest request, IResponse response)
    {
        return null;
    }

    public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        bool isRedirect)
    {
        return false;
    }

    public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
        WindowOpenDisposition targetDisposition, bool userGesture)
    {
        return false;
    }

    public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode,
        string requestUrl,
        ISslInfo sslInfo, IRequestCallback callback)
    {
        return false;
    }

    public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
    {
    }

    public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame,
        IRequest request,
        IRequestCallback callback)
    {
        return CefReturnValue.Continue;
    }

    public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy,
        string host, int port,
        string realm, string scheme, IAuthCallback callback)
    {
        return false;
    }

    public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
    {
    }

    public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize,
        IRequestCallback callback)
    {
        return false;
    }

    public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        ref string newUrl)
    {
    }

    public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
    {
        return false;
    }

    public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
    {
    }

    public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
        IResponse response)
    {
        return false;
    }
}

Problem

I'm unable to read the JSON response because stream is null.

Question

How can I read the JSON response content from a XMLHttpRequest?

I am very inexperienced in this area. So, if I have left out any useful information: please let me know and I will provide it.

Upvotes: 1

Views: 5002

Answers (1)

姚嘉辉
姚嘉辉

Reputation: 547

I have a solution.
I am using cefsharp 49.

We read it in a filter:

public class TestJsonFilter:IResponseFilter
{
    public List<byte> DataAll = new List<byte>();

    public FilterStatus Filter(System.IO.Stream dataIn, out long dataInRead, System.IO.Stream dataOut, out long dataOutWritten)
    {
        try
        {
            if (dataIn == null || dataIn.Length == 0)
            {
                dataInRead = 0;
                dataOutWritten = 0;

                return FilterStatus.Done;
            }

            dataInRead = dataIn.Length;
            dataOutWritten = Math.Min(dataInRead, dataOut.Length);

            dataIn.CopyTo(dataOut);
            dataIn.Seek(0, SeekOrigin.Begin);
            byte[] bs = new byte[dataIn.Length];
            dataIn.Read(bs, 0, bs.Length);
            DataAll.AddRange(bs);

            dataInRead = dataIn.Length;
            dataOutWritten = dataIn.Length;

            return FilterStatus.NeedMoreData;
        }
        catch (Exception ex)
        {
            dataInRead = dataIn.Length;
            dataOutWritten = dataIn.Length;

            return FilterStatus.Done;
        }
    }

    public bool InitFilter()
    {
        return true;
    }

    public void Dispose()
    {

    }
}

public class FilterManager
{
    private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();

    public static IResponseFilter CreateFilter(string guid)
    {
        lock (dataList)
        {
            var filter = new TestJsonFilter();
            dataList.Add(guid, filter);

            return filter;
        }
    }

    public static IResponseFilter GetFileter(string guid)
    {
        lock (dataList)
        {
            return dataList[guid];
        }
    }
}

and in class DefaultRequestHandler : IRequestHandler we implement methods below.

public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame,
    IRequest request, IResponse response)
{
    /*if (request.Headers["X-Requested-With"] != "XMLHttpRequest" ||
        response.ResponseHeaders["Content-Type"].Contains("application/json")) return null;*/

    if (!response.ResponseHeaders["Content-Type"].Contains("application/json"))
    {
        return null;
    }

    var filter = FilterManager.CreateFilter(request.Identifier.ToString());

    return filter;
}

public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request,
    IResponse response, UrlRequestStatus status, long receivedContentLength)
{
    if (!response.ResponseHeaders["Content-Type"].Contains("application/json"))
    {
        return;
    }

    var filter = FilterManager.GetFileter(request.Identifier.ToString()) as TestJsonFilter;

    if (filter != null)
        Console.WriteLine(filter.DataAll);
}

The filter.dataAll is what we need! We can display the string using something like:

ASCIIEncoding encoding = new ASCIIEncoding();
string data = encoding.GetString(filter.DataAll.ToArray());
Console.WriteLine(data);

finally use it in your form.

var wb = new ChromiumWebBrowser("http://www.bilibili.com/video/av8503878/")
         {
            Dock = DockStyle.Fill,
            RequestHandler = new DefaultRequestHandler()
         };

Upvotes: 4

Related Questions