Chrome Sendrequest त्रुटि: TypeError: JSON को परिपत्र संरचना परिवर्तित करना


382

मुझे निम्नलिखित मिला है ...

chrome.extension.sendRequest({
  req: "getDocument",
  docu: pagedoc,
  name: 'name'
}, function(response){
  var efjs = response.reply;
});

जो निम्नलिखित कॉल करता है ..

case "getBrowserForDocumentAttribute":
  alert("ZOMG HERE");
  sendResponse({
    reply: getBrowserForDocumentAttribute(request.docu,request.name)
  });
  break;

हालाँकि, मेरा कोड कभी भी "ZOMG HERE" तक नहीं पहुंचता, बल्कि दौड़ते समय निम्नलिखित त्रुटि को फेंकता है chrome.extension.sendRequest

 Uncaught TypeError: Converting circular structure to JSON
 chromeHidden.JSON.stringify
 chrome.Port.postMessage
 chrome.initExtension.chrome.extension.sendRequest
 suggestQuery

किसी को भी पता है कि यह क्या कारण है?


2
आप एक ऐसी वस्तु भेजने की कोशिश कर रहे हैं जिसमें परिपत्र संदर्भ हों। क्या है pagedoc?
फेलिक्स क्लिंग

9
मुझे क्या मतलब है? 1. का मूल्य क्या है pagedoc? 2. परिपत्र संदर्भ:a = {}; a.b = a;
फेलिक्स क्लिंग

1
आह .. कि यह तय! यदि आप एक उत्तर देना चाहते हैं तो मैं आपको इसका श्रेय दूंगा!
स्कीज़िट

5
नोड का उपयोग करने की कोशिश करें। जेएस: use.inspect
बोल्डनिक

जवाबों:


488

इसका अर्थ है कि आप जिस वस्तु को अनुरोध में पास करते हैं (मुझे लगता है कि यह है pagedoc) का एक परिपत्र संदर्भ है, कुछ इस तरह है:

var a = {};
a.b = a;

JSON.stringify इस तरह संरचनाओं को परिवर्तित नहीं किया जा सकता है।

एनबी : यह डोम नोड्स के साथ मामला होगा, जिनके पास परिपत्र संदर्भ हैं, भले ही वे डोम ट्री से संलग्न न हों। प्रत्येक नोड में अधिकांश मामलों ownerDocumentको संदर्भित करता है documentdocumentके माध्यम से कम से कम डोम पेड़ के लिए एक संदर्भ है document.bodyऔर document.body.ownerDocumentवापस करने के लिए संदर्भित करता है documentफिर से है, जो केवल है एक डोम पेड़ में एक से अधिक वृत्तीय संदर्भ की।


2
धन्यवाद! यह उस मुद्दे की व्याख्या करता है जो मुझे मिला। लेकिन डोम ऑब्जेक्ट्स में मौजूद परिपत्र संदर्भ किसी भी मुद्दे का कारण कैसे नहीं बनता है? क्या JSON किसी documentऑब्जेक्ट को कड़ा करेगा ?
asgs

3
@asgs: यह करता है कम से कम Chrome में, मुद्दों कारण। फ़ायरफ़ॉक्स इसके बारे में थोड़ा चालाक लगता है, लेकिन मुझे नहीं पता कि यह क्या कर रहा है।
फेलिक्स क्लिंग

क्या इस त्रुटि को "पकड़ना" और इसे संभालना संभव है?
डॉग मोलिनक्स

2
@DougMolineux: निश्चित रूप से, आप try...catchइस त्रुटि को पकड़ने के लिए उपयोग कर सकते हैं ।
फेलिक्स क्लिंग

4
@FelixKling दुर्भाग्य से मुझे वह काम नहीं मिला (हो सकता है कि कुछ गलत कर रहा हो) मैंने इसका उपयोग करके समाप्त किया: github.com/isaacs/json-stringify-safe
डौग मोलिनक्स

128

मोज़िला में JSON डॉक्स के अनुसार , JSON.Stringifyएक दूसरा पैरामीटर है censorजिसका उपयोग पेड़ को पार्स करते समय बच्चों की वस्तुओं को फ़िल्टर / अनदेखा करने के लिए किया जा सकता है। हालांकि, शायद आप परिपत्र संदर्भों से बच सकते हैं।

Node.js में हम नहीं कर सकते। तो हम ऐसा कुछ कर सकते हैं:

function censor(censor) {
  var i = 0;

  return function(key, value) {
    if(i !== 0 && typeof(censor) === 'object' && typeof(value) == 'object' && censor == value) 
      return '[Circular]'; 

    if(i >= 29) // seems to be a harded maximum of 30 serialized objects?
      return '[Unknown]';

    ++i; // so we know we aren't using the original object anymore

    return value;  
  }
}

var b = {foo: {bar: null}};

b.foo.bar = b;

console.log("Censoring: ", b);

console.log("Result: ", JSON.stringify(b, censor(b)));

परिणाम:

Censoring:  { foo: { bar: [Circular] } }
Result: {"foo":{"bar":"[Circular]"}}

दुर्भाग्य से वहाँ अधिकतम 30 पुनरावृत्तियों लगता है इससे पहले कि यह स्वचालित रूप से यह परिपत्र है मानता है। अन्यथा, यह काम करना चाहिए। मैंने यहां areEquivalent से भी उपयोग किया , लेकिन JSON.Stringify30 पुनरावृत्तियों के बाद भी अपवाद को फेंकता है। फिर भी, शीर्ष स्तर पर वस्तु का एक अच्छा प्रतिनिधित्व प्राप्त करना काफी अच्छा है, अगर आपको वास्तव में इसकी आवश्यकता है। हालांकि किसी को इस पर सुधार कर सकते हैं? HTTP अनुरोध वस्तु के लिए Node.js में, मुझे मिल रहा है:

{
"limit": null,
"size": 0,
"chunks": [],
"writable": true,
"readable": false,
"_events": {
    "pipe": [null, null],
    "error": [null]
},
"before": [null],
"after": [],
"response": {
    "output": [],
    "outputEncodings": [],
    "writable": true,
    "_last": false,
    "chunkedEncoding": false,
    "shouldKeepAlive": true,
    "useChunkedEncodingByDefault": true,
    "_hasBody": true,
    "_trailer": "",
    "finished": false,
    "socket": {
        "_handle": {
            "writeQueueSize": 0,
            "socket": "[Unknown]",
            "onread": "[Unknown]"
        },
        "_pendingWriteReqs": "[Unknown]",
        "_flags": "[Unknown]",
        "_connectQueueSize": "[Unknown]",
        "destroyed": "[Unknown]",
        "bytesRead": "[Unknown]",
        "bytesWritten": "[Unknown]",
        "allowHalfOpen": "[Unknown]",
        "writable": "[Unknown]",
        "readable": "[Unknown]",
        "server": "[Unknown]",
        "ondrain": "[Unknown]",
        "_idleTimeout": "[Unknown]",
        "_idleNext": "[Unknown]",
        "_idlePrev": "[Unknown]",
        "_idleStart": "[Unknown]",
        "_events": "[Unknown]",
        "ondata": "[Unknown]",
        "onend": "[Unknown]",
        "_httpMessage": "[Unknown]"
    },
    "connection": "[Unknown]",
    "_events": "[Unknown]",
    "_headers": "[Unknown]",
    "_headerNames": "[Unknown]",
    "_pipeCount": "[Unknown]"
},
"headers": "[Unknown]",
"target": "[Unknown]",
"_pipeCount": "[Unknown]",
"method": "[Unknown]",
"url": "[Unknown]",
"query": "[Unknown]",
"ended": "[Unknown]"
}

मैंने यह करने के लिए एक छोटा सा Node.js मॉड्यूल बनाया है: https://github.com/ericmuyser/stringy सुधार / योगदान के लिए स्वतंत्र महसूस करें!


10
यह पहली बार है जब मैं एक फ़ंक्शन पास हो रहा हूँ जो एक स्व-निष्पादित फ़ंक्शन देता है जो एक नियमित फ़ंक्शन देता है। मेरा मानना ​​है कि मैं समझता हूं कि यह क्यों किया गया था, लेकिन मुझे विश्वास नहीं होता कि मुझे वह समाधान खुद मिल गया होगा, और मुझे लगता है कि मैं इस तकनीक को बेहतर ढंग से याद रख सकता हूं अगर मैं अन्य उदाहरण देख सकता हूं जहां इस सेटअप की आवश्यकता है। कहा जा रहा है, क्या आप इस सेटअप / तकनीक (बेहतर शब्द की कमी के लिए) या इसी तरह के किसी भी साहित्य की ओर इशारा कर सकते हैं?
शॉन

1
+1 से शॉन। कृपया उस IEFE को हटा दें, यह बिल्कुल बेकार और अवैध है।
बर्गी

1
सेंसर की ओर इशारा करने के लिए thx! यह परिपत्र मुद्दों को डीबग करने की अनुमति देता है। मेरे मामले में मेरे पास एक jquery सरणी थी जहां मैं एक सामान्य सरणी रखता था। वे दोनों डिबग प्रिंट मोड में समान दिखते हैं। IEFE के बारे में, मैं उन्हें अक्सर उन जगहों पर उपयोग करते हुए देखता हूं, जहां उनके लिए बिल्कुल कोई आवश्यकता नहीं है और शॉन और बर्गी से सहमत हैं कि यह सिर्फ ऐसा मामला है।
शहरकीड

1
मुझे यकीन नहीं है कि क्यों, लेकिन यह समाधान मेरे लिए काम नहीं करता है।
निकोला शॉ

1
@BrunoLM: 30 पुनरावृत्तियों की सीमा के लिए, यदि आप वापस लौटते '[Unknown:' + typeof(value) + ']'हैं तो आप देखेंगे कि सेंसर को ठीक से कार्यों और कुछ अन्य प्रकारों को कैसे ठीक किया जाए।
एलेक्स पाक्का

46

एक दृष्टिकोण मुख्य वस्तु से वस्तु और कार्यों को छीनना है। और सरल रूप को कठोर करें

function simpleStringify (object){
    var simpleObject = {};
    for (var prop in object ){
        if (!object.hasOwnProperty(prop)){
            continue;
        }
        if (typeof(object[prop]) == 'object'){
            continue;
        }
        if (typeof(object[prop]) == 'function'){
            continue;
        }
        simpleObject[prop] = object[prop];
    }
    return JSON.stringify(simpleObject); // returns cleaned up JSON
};

2
मेरे लिए बिल्कुल सही जवाब। शायद 'फ़ंक्शन' कीवर्ड छूट गया?
Stepan Loginov

28

मैं आम तौर पर इसे हल करने के लिए परिपत्र- json npm पैकेज का उपयोग करता हूं।

// Felix Kling's example
var a = {};
a.b = a;
// load circular-json module
var CircularJSON = require('circular-json');
console.log(CircularJSON.stringify(a));
//result
{"b":"~"}

नोट: वृत्ताकार जोंस को हटा दिया गया है, अब मैं चपटा (सर्कुलरजोन के निर्माता से) का उपयोग करता हूं:

// ESM
import {parse, stringify} from 'flatted/esm';

// CJS
const {parse, stringify} = require('flatted/cjs');

const a = [{}];
a[0].a = a;
a.push(a);

stringify(a); // [["1","0"],{"a":"0"}]

से: https://www.npmjs.com/package/flatted


8

ज़ैनगिनेर के उत्तर के आधार पर ... एक अन्य दृष्टिकोण ऑब्जेक्ट की एक गहरी प्रतिलिपि बनाने और परिपत्र संदर्भों को स्ट्रिप करने और परिणाम को संशोधित करने के लिए है।

function cleanStringify(object) {
    if (object && typeof object === 'object') {
        object = copyWithoutCircularReferences([object], object);
    }
    return JSON.stringify(object);

    function copyWithoutCircularReferences(references, object) {
        var cleanObject = {};
        Object.keys(object).forEach(function(key) {
            var value = object[key];
            if (value && typeof value === 'object') {
                if (references.indexOf(value) < 0) {
                    references.push(value);
                    cleanObject[key] = copyWithoutCircularReferences(references, value);
                    references.pop();
                } else {
                    cleanObject[key] = '###_Circular_###';
                }
            } else if (typeof value !== 'function') {
                cleanObject[key] = value;
            }
        });
        return cleanObject;
    }
}

// Example

var a = {
    name: "a"
};

var b = {
    name: "b"
};

b.a = a;
a.b = b;

console.log(cleanStringify(a));
console.log(cleanStringify(b));


6

यह संबंधित उत्तर नहीं हो सकता है, लेकिन यह लिंक जावास्क्रिप्ट में परिपत्र संदर्भों का पता लगाने और तय करने से उन वस्तुओं का पता लगाने में मददगार हो सकता है जो परिपत्र निर्भरता पैदा कर रहे हैं।


4

मैं इस तरह NodeJS पर इस समस्या को हल करता हूं:

var util = require('util');

// Our circular object
var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: 'Yo!'}}}}}}}};
obj.foo.bar = obj;

// Generate almost valid JS object definition code (typeof string)
var str = util.inspect(b, {depth: null});

// Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case)
str = str
    .replace(/<Buffer[ \w\.]+>/ig, '"buffer"')
    .replace(/\[Function]/ig, 'function(){}')
    .replace(/\[Circular]/ig, '"Circular"')
    .replace(/\{ \[Function: ([\w]+)]/ig, '{ $1: function $1 () {},')
    .replace(/\[Function: ([\w]+)]/ig, 'function $1(){}')
    .replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, '$1: new Date("$2"),')
    .replace(/(\S+): ,/ig, '$1: null,');

// Create function to eval stringifyed code
var foo = new Function('return ' + str + ';');

// And have fun
console.log(JSON.stringify(foo(), null, 4));

2

JQuery के साथ नीचे दिए गए संदेश को बनाने की कोशिश करते समय मैंने उसी त्रुटि का अनुभव किया है। परिपत्र संदर्भ तब होता है जब reviewerNameगलती से सौंपा जा रहा था msg.detail.reviewerName। JQuery की .val () समस्या को ठीक किया, अंतिम पंक्ति देखें।

var reviewerName = $('reviewerName'); // <input type="text" id="taskName" />;
var msg = {"type":"A", "detail":{"managerReview":true} };
msg.detail.reviewerName = reviewerName; // Error
msg.detail.reviewerName = reviewerName.val(); // Fixed

1

मुझे jQuery formvaliadator के साथ एक ही त्रुटि मिल रही थी, लेकिन जब मैंने सफलता के अंदर एक कंसोल.लॉग हटा दिया: फ़ंक्शन, यह काम किया।


0

मेरे मामले के लिए मैं उस त्रुटि को प्राप्त कर रहा था जब मैं asyncअपने सर्वर-साइड पर फ़ंक्शन का उपयोग कर रहा था, जिसमें मूंगोज़ का उपयोग करके दस्तावेज़ लाने के लिए। यह पता चला कि इसका कारण यह था कि मैं awaitकॉलिंग find({})विधि से पहले रखना भूल गया था । उस हिस्से को जोड़कर मेरे मुद्दे को तय किया।


0

यह काम करता है और आपको बताता है कि कौन से गुण परिपत्र हैं। यह ऑब्जेक्ट को संदर्भों के साथ पुनर्निर्माण करने की भी अनुमति देता है

  JSON.stringifyWithCircularRefs = (function() {
    const refs = new Map();
    const parents = [];
    const path = ["this"];

    function clear() {
      refs.clear();
      parents.length = 0;
      path.length = 1;
    }

    function updateParents(key, value) {
      var idx = parents.length - 1;
      var prev = parents[idx];
      if (prev[key] === value || idx === 0) {
        path.push(key);
        parents.push(value);
      } else {
        while (idx-- >= 0) {
          prev = parents[idx];
          if (prev[key] === value) {
            idx += 2;
            parents.length = idx;
            path.length = idx;
            --idx;
            parents[idx] = value;
            path[idx] = key;
            break;
          }
        }
      }
    }

    function checkCircular(key, value) {
      if (value != null) {
        if (typeof value === "object") {
          if (key) { updateParents(key, value); }

          let other = refs.get(value);
          if (other) {
            return '[Circular Reference]' + other;
          } else {
            refs.set(value, path.join('.'));
          }
        }
      }
      return value;
    }

    return function stringifyWithCircularRefs(obj, space) {
      try {
        parents.push(obj);
        return JSON.stringify(obj, checkCircular, space);
      } finally {
        clear();
      }
    }
  })();

शोर के बहुत से उदाहरण निकाले गए:

{
    "requestStartTime": "2020-05-22...",
    "ws": {
        "_events": {},
        "readyState": 2,
        "_closeTimer": {
            "_idleTimeout": 30000,
            "_idlePrev": {
                "_idleNext": "[Circular Reference]this.ws._closeTimer",
                "_idlePrev": "[Circular Reference]this.ws._closeTimer",
                "expiry": 33764,
                "id": -9007199254740987,
                "msecs": 30000,
                "priorityQueuePosition": 2
            },
            "_idleNext": "[Circular Reference]this.ws._closeTimer._idlePrev",
            "_idleStart": 3764,
            "_destroyed": false
        },
        "_closeCode": 1006,
        "_extensions": {},
        "_receiver": {
            "_binaryType": "nodebuffer",
            "_extensions": "[Circular Reference]this.ws._extensions",
        },
        "_sender": {
            "_extensions": "[Circular Reference]this.ws._extensions",
            "_socket": {
                "_tlsOptions": {
                    "pipe": false,
                    "secureContext": {
                        "context": {},
                        "singleUse": true
                    },
                },
                "ssl": {
                    "_parent": {
                        "reading": true
                    },
                    "_secureContext": "[Circular Reference]this.ws._sender._socket._tlsOptions.secureContext",
                    "reading": true
                }
            },
            "_firstFragment": true,
            "_compress": false,
            "_bufferedBytes": 0,
            "_deflating": false,
            "_queue": []
        },
        "_socket": "[Circular Reference]this.ws._sender._socket"
    }
}

कॉल करने के लिए JSON.parse () फिर [Circular Reference]टैग की तलाश करने वाली संपत्तियों के माध्यम से लूप करें । फिर उस काट और ... eval ... यह thisरूट ऑब्जेक्ट के लिए सेट के साथ ।

कुछ भी है कि हैक किया जा सकता है eval मत करो। बेहतर अभ्यास करना होगा string.split('.')कि संदर्भ सेट करने के लिए गुणों को नाम से देखें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.