การกำหนดฟังก์ชันในผลลัพธ์ JSON ถูกต้องหรือไม่


98

ส่วนหนึ่งของการตอบสนอง JSON ของเว็บไซต์มีสิ่งนี้ (... เพิ่มสำหรับบริบท):

{..., now:function(){return(new Date).getTime()}, ...}

การเพิ่มฟังก์ชันที่ไม่ระบุชื่อให้กับ JSON นั้นถูกต้องหรือไม่ ฉันคาดว่าทุกครั้งที่คุณเข้าถึง 'เวลา' จะส่งคืนค่าที่แตกต่างกัน


เบราว์เซอร์แยกวิเคราะห์ JSON สำเร็จหรือไม่ ถ้าเป็นเช่นนั้นใช่ถือว่าถูกต้อง (ในแง่นั้น)
harschware

7
@harschware - นั่นเป็นจริงเฉพาะเมื่อ JSON เกี่ยวข้องกับจาวาสคริปต์ เนื่องจากรูปแบบการจัดลำดับข้อมูลที่ไม่ขึ้นกับภาษาจึงเป็นเท็จและเป็นเส้นทางที่มีปัญหาในการเดินลง
jsoverson

@jsoverson - ฉันเห็นด้วย ดูคำตอบของฉันด้านล่าง
harschware

1
ง่ายที่จะตอบคำถามนี้ด้วยตัวเอง: JSON.parse('{now:function(){return(new Date).getTime()}')เปิดขึ้นชุดเว็บตรวจสอบและเรียกใช้: ผู้ตรวจสอบกล่าวว่า: ข้อมูลจำเพาะ JSONUncaught SyntaxError: Unexpected token nอย่างรวดเร็วช่วยยืนยันสิ่งนี้ เน้นที่ส่วน 'ค่า'
Mark E.Haase

คำตอบ:


103

ไม่

JSON มีไว้เพื่อเป็นภาษาอธิบายข้อมูลเท่านั้น ตามที่ระบุไว้ในhttp://www.json.orgเป็น "รูปแบบการแลกเปลี่ยนข้อมูลที่มีน้ำหนักเบา" - ไม่ใช่ภาษาโปรแกรม

ตามhttp://en.wikipedia.org/wiki/JSON "ประเภทพื้นฐาน" ที่รองรับ ได้แก่ :

  • จำนวน (จำนวนเต็มจริงหรือทศนิยม)
  • สตริง (Unicode ที่ยกมาสองครั้งพร้อมแบ็กสแลช Escape)
  • บูลีน (จริงและเท็จ)
  • อาร์เรย์ (ลำดับของค่าที่เรียงลำดับโดยคั่นด้วยเครื่องหมายจุลภาคและอยู่ในวงเล็บเหลี่ยม)
  • วัตถุ (คอลเลกชันของคีย์: คู่ค่าคั่นด้วยจุลภาคและอยู่ในวงเล็บปีกกา)
  • null

2
@ ดร. Zim ไม่ใช่และเพื่อเปรียบเทียบสิ่งต่าง ๆ กับโมฆะสิ่งที่ฉันทำคือนี่a==null?1:a.toString()==""สิ่งนี้จะบอกว่าถ้า a = null มันจะส่งกลับ 1 / จริงถ้าเป็น "" หมายถึงสตริงว่างคุณจะได้ 1 / จริงด้วย .. ถ้าเป็น ไม่เป็นค่าว่างหรือ "" จากนั้นจะส่งคืนค่า 0 / เท็จคุณสามารถจำลองสิ่งนี้ได้มากขึ้นเพื่อใช้กับ [] และ {} เพียงแค่เพิ่ม?1:a==[]?1:a.toString()=={}.toString();ลงในตัวอย่างข้อมูลก่อนหน้าของฉัน ดังนั้นบางทีฟังก์ชันนี้จะช่วยคุณได้ isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})ฉันจะใช้?1:0แทน?true:falseแต่ (จริง / เท็จ)
JamesM-SiteGen

11
ในขณะเดียวกันฟังก์ชันก็เป็นข้อมูลเช่นกัน
argyle

2
ฉันมาถึงที่นี่ในขณะที่หาวิธีดึง "ข้อมูลเพิ่มเติม" โดยใช้ JSON เป็นการดีที่จะแจ้งให้ไคลเอนต์ (จากเซิร์ฟเวอร์) ทราบถึงวิธีการรับข้อมูลเพิ่มเติมโดยที่ลูกค้าไม่ต้องกังวลว่า REST หรือ api ใดที่จะเรียกต่อไป
Ravindranath Akila

3
@RavindranathAkila REST บอกเป็นนัยว่าอาจมีการเรียก API ครั้งต่อไปในการโทร กล่าวอีกนัยหนึ่ง: คำขอ REST ที่คุณทำจะบอกคุณว่าคำขอใดในอนาคตที่คุณอาจต้องการทำ (ขึ้นอยู่กับตรรกะการตัดสินใจของแอปพลิเคชันและข้อมูล) ตัวอย่างที่สมบูรณ์แบบสำหรับสิ่งนี้คือ Github API ซึ่งจะส่งคืนองค์ประกอบข้อมูล แต่บางส่วนนำไปสู่ทรัพยากรคำขอ API อื่น ๆ
Jens

1
@ Jens-AndréKochขอบคุณ! จะตรวจสอบ
Ravindranath Akila

16

ปัญหาคือ JSON เป็นภาษานิยามข้อมูลพัฒนาจาก JSON เป็น JavaScript Object Notation เนื่องจาก Javascript รองรับ eval บน JSON การใส่โค้ด JSON ภายใน JSON จึงเป็นเรื่องที่ถูกต้อง หากคุณใช้ JSON เพื่อส่งผ่านข้อมูลจากระยะไกลฉันจะบอกว่าการวางเมธอดใน JSON เป็นวิธีปฏิบัติที่ไม่ดีเนื่องจากคุณอาจไม่ได้จำลองการโต้ตอบไคลเอนต์เซิร์ฟเวอร์ของคุณได้ดี และยิ่งไปกว่านั้นเมื่อต้องการใช้ JSON เป็นภาษาอธิบายข้อมูลฉันจะบอกว่าคุณอาจมีปัญหาในการฝังวิธีการเนื่องจากตัวแยกวิเคราะห์ JSON บางตัวเขียนโดยคำนึงถึงคำอธิบายข้อมูลเท่านั้นและอาจไม่รองรับคำจำกัดความของวิธีการในโครงสร้าง

รายการ Wikipedia JSONเป็นกรณีที่ดีสำหรับการไม่รวมเมธอดใน JSON โดยอ้างถึงปัญหาด้านความปลอดภัย:

เว้นแต่คุณจะเชื่อถือแหล่งที่มาของข้อความอย่างแท้จริงและคุณจำเป็นต้องแยกวิเคราะห์และยอมรับข้อความที่ไม่สอดคล้องกับ JSON อย่างเคร่งครัดคุณควรหลีกเลี่ยง eval () และใช้ JSON.parse () หรือตัวแยกวิเคราะห์เฉพาะ JSON อื่นแทน โปรแกรมแยกวิเคราะห์ JSON จะรับรู้เฉพาะข้อความ JSON และจะปฏิเสธข้อความอื่นซึ่งอาจมี JavaScript ที่เป็นอันตราย ในเบราว์เซอร์ที่รองรับ JSON แบบเนทีฟตัวแยกวิเคราะห์ JSON ยังเร็วกว่า eval มาก คาดว่าการสนับสนุน JSON ดั้งเดิมจะรวมอยู่ในมาตรฐาน ECMAScript ถัดไป


2
คุณอาจใช้คำว่า JSON เป็นภาษาเรียกขาน แต่ "JSON" อย่างเป็นทางการคือมาตรฐาน ECMA ที่ไม่ได้ระบุอ็อบเจ็กต์ฟังก์ชันที่จะเข้ารหัส ไม่ควรมีความคลุมเครือเกี่ยวกับความสามารถที่คุณอ้างถึงเมื่อคุณพูดว่า "JSON" นั่นคือจุดรวมของการมีมาตรฐาน
Mark E.Haase

ตกลงว่าเป็นจริงวันนี้. ฉันไม่มีแหล่งที่จะอ้างอิง แต่ฉันเชื่อว่า JSON เป็นคำที่บัญญัติขึ้นก่อนที่ ECMA จะเข้ามาในเกม Javascript และก่อนที่ JSON จะเป็นรูปแบบการแลกเปลี่ยนข้อมูลมาตรฐาน ... ดังนั้นฉันจึงใช้คำว่า 'วิวัฒนาการ'
harschware

@harschware อ้างอิงจาก RFC 4627 JSON ถูกสร้างขึ้นจาก ECMA
Jenna Sloan

9

ขออ้างหนึ่งในข้อมูลจำเพาะ - http://tools.ietf.org/html/rfc7159#section-12

วัตถุ JavaScript โน้ต (JSON) Data Interchange รูปแบบจำเพาะฯ :

JSON เป็นส่วนย่อยของ JavaScript แต่ไม่รวมการมอบหมายและการเรียกใช้

เนื่องจากไวยากรณ์ของ JSON ยืมมาจาก JavaScript จึงสามารถใช้ฟังก์ชัน "eval ()" ของภาษานั้นเพื่อแยกวิเคราะห์ข้อความ JSON ได้ ซึ่งมักจะถือว่าเป็นความเสี่ยงที่ยอมรับไม่ได้เนื่องจากข้อความที่
อาจมีรหัสปฏิบัติการพร้อมกับการประกาศข้อมูล การพิจารณาเดียวกันนี้ใช้กับการใช้ฟังก์ชันเหมือน eval () ในภาษาการเขียนโปรแกรมอื่น ๆ ซึ่งข้อความ JSON เป็นไปตาม
ไวยากรณ์ของภาษานั้น

ดังนั้นคำตอบทั้งหมดที่ระบุว่าฟังก์ชันนั้นไม่ได้เป็นส่วนหนึ่งของมาตรฐาน JSON นั้นถูกต้อง

คำตอบอย่างเป็นทางการคือไม่ไม่สามารถกำหนดฟังก์ชันในผลลัพธ์ JSON ได้!


คำตอบอาจเป็นได้เพราะ "code is data" และ "data is code" แม้ว่า JSON จะถูกใช้เป็นรูปแบบการจัดลำดับข้อมูลที่ไม่ขึ้นกับภาษา แต่การสร้าง "โค้ด" ผ่านประเภทอื่น ๆ ก็จะใช้ได้

อาจใช้สตริง JSON เพื่อส่งผ่านฟังก์ชัน JS ไปยังเบราว์เซอร์ฝั่งไคลเอ็นต์เพื่อดำเนินการ

[{"data":[["1","2"],["3","4"]],"aFunction":"function(){return \"foo bar\";}"}]

สิ่งนี้นำไปสู่คำถามเช่น: วิธี " รันโค้ด JavaScript ที่จัดเก็บเป็นสตริง "

เตรียมพร้อมที่จะเพิ่มแฟล็ก "eval () is evil" ของคุณและติดแฟล็ก "do not tunnel ผ่าน JSON" ไว้ข้างๆ



4

ไม่ไม่แน่นอน

หากคุณใช้ซีเรียลไลเซอร์ JSON ที่เหมาะสมมันจะไม่ยอมให้คุณจัดลำดับฟังก์ชันเช่นนั้น เป็น OBJECT ที่ถูกต้อง แต่ไม่ใช่ JSON ที่ถูกต้อง ไม่ว่าเว็บไซต์นั้นจะมีเจตนาอย่างไรก็ไม่ได้ส่ง JSON ที่ถูกต้อง


2
ฉันใช้ JSON-Lib และคิดว่ามันเป็น serializer ที่ยอดเยี่ยม จาก [หน้าการใช้งาน] (json-lib.sourceforge.net/usage.html) คุณจะเห็นว่ามันจะทำให้ฟังก์ชันเป็นอนุกรมได้ดี
harschware

น่าสนใจ ... ไม่เคยเห็นมาก่อน แน่นอนว่าไม่จำเป็นต้องระบุ ( json.orgระบุอย่างชัดเจนว่า JSON เป็นภาษาที่ไม่ขึ้นกับภาษาซึ่งไม่ใช่คำจำกัดความของฟังก์ชัน) แต่ก็น่าสนใจ
jvenema

มันตลกดีที่มันควรจะเป็นภาษาที่ไม่ขึ้นกับภาษา แต่ JSON ย่อมาจาก JavaScript Object Notation อืมแปลก ..
Nate-Wilkins

3

JSON ไม่รวมฟังก์ชันอย่างชัดเจนเนื่องจากไม่ได้หมายถึงโครงสร้างข้อมูล JavaScript เท่านั้น (แม้จะมี JS อยู่ในชื่อก็ตาม)


3

คำตอบสั้น ๆ คือไม่ ...

JSON เป็นรูปแบบข้อความที่เป็นภาษาที่เป็นอิสระโดยสิ้นเชิง แต่ใช้รูปแบบที่คุ้นเคยกับโปรแกรมเมอร์ของภาษาตระกูล C ได้แก่ C, C ++, C #, Java, JavaScript, Perl, Python และอื่น ๆ อีกมากมาย คุณสมบัติเหล่านี้ทำให้ JSON เป็นภาษาแลกเปลี่ยนข้อมูลในอุดมคติ

ดูเหตุผลว่าทำไม:

เมื่อแลกเปลี่ยนข้อมูลระหว่างเบราว์เซอร์และเซิร์ฟเวอร์ข้อมูลจะต้องเป็นข้อความเท่านั้น

JSON เป็นข้อความและเราสามารถแปลงวัตถุ JavaScript เป็น JSON และส่ง JSON ไปยังเซิร์ฟเวอร์

เรายังสามารถแปลง JSON ที่ได้รับจากเซิร์ฟเวอร์เป็นวัตถุ JavaScript

ด้วยวิธีนี้เราสามารถทำงานกับข้อมูลเป็นวัตถุ JavaScript โดยไม่มีการแยกวิเคราะห์และการแปลที่ซับซ้อน

แต่เดี๋ยวก่อน ...

ยังมีหลายวิธีในการจัดเก็บฟังก์ชันของคุณจึงไม่แนะนำอย่างกว้างขวางแต่ก็ยังทำได้:

เราบอกว่าคุณสามารถบันทึกstring... แล้วการแปลงฟังก์ชันของคุณเป็นสตริงล่ะ?

const data = {func: '()=>"a FUNC"'};

จากนั้นคุณสามารถสตริงข้อมูลโดยใช้JSON.stringify(data)แล้วใช้JSON.parseเพื่อแยกวิเคราะห์ (หากจำเป็นขั้นตอนนี้) ...

และEVALที่จะดำเนินการฟังก์ชั่นสตริง (ก่อนที่จะทำนั้นเพียงแค่ให้คุณรู้ว่าการใช้กันอย่างแพร่หลาย EVAL ไม่แนะนำ):

eval(data.func)(); //return "a FUNC"

0

ด้วยการใช้ NodeJS (ไวยากรณ์ commonJS) ฉันสามารถทำให้ฟังก์ชันประเภทนี้ทำงานได้เดิมทีฉันมีเพียงโครงสร้าง JSON ภายในไฟล์ JS ภายนอกบางไฟล์ แต่ฉันต้องการให้โครงสร้างนั้นเป็นคลาสมากกว่าโดยมีวิธีการที่สามารถตัดสินใจได้ที่ เวลาทำงาน

ไม่จำเป็นต้องมีการประกาศ 'Executor' ใน myJSON

var myJSON = {
    "Hello": "World",
    "Executor": ""
}

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}

-3

นิพจน์ฟังก์ชันใน JSON เป็นไปได้อย่างสมบูรณ์อย่าลืมใส่เครื่องหมายอัญประกาศคู่ นี่คือตัวอย่างที่นำมาจากการออกแบบฐานข้อมูล noSQL:

{
  "_id": "_design/testdb",
  "views": {
    "byName": {
      "map": "function(doc){if(doc.name){emit(doc.name,doc.code)}}"
    }
  }
}


คำถามเกี่ยวกับฟังก์ชันไม่ใช่สตริง JSON รองรับค่าสตริง แต่ไม่รองรับฟังก์ชัน ดูคำตอบของ Mikeสำหรับรายละเอียด
jannis

@jannis เป็นไปได้แม้ว่า หากคุณเพิ่มฟังก์ชันเรียกตัวเองเช่น. ผู้คนที่นี่ดูเหมือนจะไม่รู้คำตอบ
โรจน์

-4

แม้ว่าจะไม่แนะนำให้ใช้ eval แต่ก็ใช้ได้ผล:

<!DOCTYPE html>
<html>
<body>

<h2>Convert a string written in JSON format, into a JavaScript function.</h2>

<p id="demo"></p>

<script>
    function test(val){return val + " it's OK;}
    var someVar = "yup";
    var myObj = { "func": "test(someVar);" };
    document.getElementById("demo").innerHTML = eval(myObj.func);
</script>

</body>
</html>

1
ลงคะแนนเนื่องจากไม่จำเป็นต้องใช้ HTML ในตัวอย่างนี่เป็นรูปแบบการเข้ารหัสที่เก่ากว่า 5 ปีมีเครื่องหมายคำพูดที่ขาดหายไปและไฟล์ JSON ไม่ควรมีฟังก์ชันหากไม่สามารถทำให้เป็นอนุกรมหรือเก็บไว้ใน ไม่มี sql DB,
Martijn Scheffer

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.