简体   繁体   English

如何在Angular $ http响应中捕获格式错误的JSON?

[英]How to catch malformed JSON in an Angular $http response?

Update: Code updated with the solution based on Eamonn Gahan's answer 更新:使用基于Eamonn Gahan答案的解决方案更新代码

I'm trying to fetch some files that are user generated and can't be trusted to be properly formatted. 我正在尝试获取一些用户生成的文件,并且无法将其置于格式正确的文件中。 I thought this would be straightforward, but I'm stumped on what to do when the response is kind of like JSON, but isn't. 我认为这很简单,但是当我的回答有点像JSON时,我很难做什么,但事实并非如此。

For example if a server responds with: a simple string {with brackets} everything works as expected. 例如,如果服务器响应: a simple string {with brackets}一切都按预期工作。 But, if the server responds with: { not_json: { malformed on purpose } , then I can't figure out how to get access to the response, either as a success or failure response. 但是,如果服务器响应: { not_json: { malformed on purpose } ,那么我无法弄清楚如何获得对响应的访问,无论是成功还是失败响应。

What seems to happen is the Angular JSON parser throws a Syntax error without rejecting the $http promise. 似乎发生的是Angular JSON解析器抛出语法错误而不拒绝$ http promise。

Below is some code that highlights the issue. 以下是一些突出问题的代码。

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $http){

    // --- Added this block based on Eamonn Gahan's answer
    function txfmParseText(data, hdrGetter){
        var contentType = hdrGetter()['content-type'];
        if ( contentType.match(/^text\/plain/) ){
            data = JSON.stringify(data);
        } 
        return data ;
    }

    $http.defaults.transformResponse.unshift(txfmParseText);
    // --- end of updated block

    $scope.sanityCheck="Alive";

    // URL returns (as text/plain):
    //   { not_json: { malformed on purpose }
    var urlOpts1 = {
        method: 'GET',
        url: 'https://s3.amazonaws.com/forforf-cdn/not_json_test'
    };

    // URL returns (as text/plain):
    //   a simple string {with brackets}
    var urlOpts2 = {
        method: 'GET',
        url: 'https://s3.amazonaws.com/forforf-cdn/simple_string_with_brackets'
    };

    // First request fails  [update: passes with transformResponse function]
    $http(urlOpts1)
    .then(function(resp){
        //never gets here
        console.log(resp);
        $scope.notJson = resp.data;
    })
    .catch(function(err){
        //nor is the promise rejected
        console.log(err)
    });

    // Second request works as expected
    $http(urlOpts2).then(function(resp){
        //works as expected
        console.log(resp);
        $scope.stringWithBrackets = resp.data;
    });

} }

and the jsFiddle jsFiddle

updated jsFiddle with solution 更新 jsFiddle与解决方案

Here's the HTTP of the failing Request and Response. 这是失败的请求和响应的HTTP。 The data is being served by S3, and the content type of the data is set to text/plain . 数据由S3提供,数据的内容类型设置为text/plain

Request URL:https://s3.amazonaws.com/forforf-cdn/not_json_test
Request Method:GET
Status Code:304 Not Modified

Request Headers
GET /forforf-cdn/not_json_test HTTP/1.1
Host: s3.amazonaws.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: application/json, text/plain, */*
Origin: http://fiddle.jshell.net
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Referer: http://fiddle.jshell.net/_display/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
If-None-Match: "84cf04d01a85ed58af77293ea7b1884a"
If-Modified-Since: Sat, 15 Feb 2014 20:52:30 GMT

Response Headers
HTTP/1.1 304 Not Modified
x-amz-id-2: FvdtpH6WmRvEAFIt3clAsXC133iyGQ/Qezlzt/5P6UDFbZvDfUC7WeuPv+re0ywE
x-amz-request-id: FA51FED4F6A70DA2
Date: Sat, 15 Feb 2014 22:02:22 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Last-Modified: Sat, 15 Feb 2014 20:52:30 GMT
ETag: "84cf04d01a85ed58af77293ea7b1884a"
Server: AmazonS3

Thinking it might be S3 wasn't setting the proper Content-Type, I also had S3 respond with: Content-Type: text/plain; charset="utf-8" 认为可能是S3没有设置正确的Content-Type,我也有S3响应: Content-Type: text/plain; charset="utf-8" Content-Type: text/plain; charset="utf-8" , but it didn't help. Content-Type: text/plain; charset="utf-8" ,但它没有帮助。

Anyone have any ideas? 有人有想法么?

This is basically happening because what angular does on a $http response is pass it through an array of functions on the $httpProvider.defaults.transformRequest property. 这基本上发生了,因为$ http响应上的angular会通过$httpProvider.defaults.transformRequest属性上的函数数组传递它。 As you can see here: https://github.com/angular/angular.js/blob/7aef2d54e0a48fae18a289813f699962d8310565/src/ng/http.js#L94 there's one default function in the array. 正如你在这里看到的: https//github.com/angular/angular.js/blob/7aef2d54e0a48fae18a289813f699962d8310565/src/ng/http.js#L94数组中有一个默认函数。 This function checks against some basic regexs to see if it should JSON.parse() the response. 此函数检查一些基本的正则表达式,以查看它是否应该响应JSON.parse()。 The malformed one unfortunately passes but you can just overwrite the transformResponse property in a config block or you can specify a transformResponse property on the actual $http call like this (from your fiddle): 遗憾的是,这个格式错误会通过,但您可以在配置块中覆盖transformResponse属性,或者您可以在实际的$http调用中指定transformResponse属性(从您的小提琴):

var urlOpts1 = { method: 'GET', url: 'https://s3.amazonaws.com/forforf-cdn/not_json_test', transformResponse: specialTransform };

http://jsfiddle.net/GBD2v/ http://jsfiddle.net/GBD2v/

In the fiddle above you can see that "{ not_json: { malformed on purpose }" gets printed as a regular string because we just returned the string straight in the custom transformResponse function. 在上面的小提琴中,您可以看到“{not_json:{malformed on purpose}”被打印为常规字符串,因为我们只是在自定义transformResponse函数中直接返回字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM