1. 程式人生 > >跨域,CORS和contentType表

跨域,CORS和contentType表

objects 文件 mod 實現 lte resp png quest 發送

一 . 跨域

域名,協議,端口有一個不一樣都是跨域,簡單的解釋一下,,你從你從端口號為8000去請求8001的數據就是跨域.
如果想解決跨域問題,需要瀏覽器同時支持,我們這裏用CORS(Cross-origin resource sharing ("跨域資源共享"))來解決跨域的問題

二 . CORS

整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。
因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨域通信。

  瀏覽器將CORS分為兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)

  只要同時
滿足一下兩個條件,就屬於簡單請求

(1) 請求方法是以下三種方法之一:(也就是說如果你的請求方法是什麽put、delete等肯定是非簡單請求)
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:(如果比這些請求頭多,那麽一定是非簡單請求)
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain,
  也就是說,如果你發送的application/json格式的數據,那麽肯定是非簡單請求,vue的axios默認的請求體信息格式是json的,ajax默認是urlencoded的。

  解決辦法(在被請求的視圖函數中加上一個響應頭信息)

from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
def books(request):

    obj = JsonResponse([西遊記2,三國演義2,水滸傳2],safe=False)
    #下面這個響應頭信息是告訴瀏覽器,"*" 代表誰請求都可以
    # obj["Access-Control-Allow-Origin"] = "*"
obj["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000" #只有這個ip和端口來的請求,我才給他數據,其他你瀏覽器幫我攔著 return obj

  非簡單請求

    這裏簡單的介紹一下簡單請求與非簡單請求的區別

* 簡單請求和非簡單請求的區別?

   簡單請求:一次請求
   非簡單請求:兩次請求,在發送數據之前會先發一次請求用於做“預檢”,只有“預檢”通過後才再發送一次請求用於數據傳輸。
* 關於“預檢”

- 請求方式:OPTIONS
- “預檢”其實做檢查,檢查如果通過則允許傳輸數據,檢查不通過則不再發送真正想要發送的消息
- 如何“預檢”
     => 如果復雜請求是PUT等請求,則服務端需要設置允許某請求,否則“預檢”不通過
        Access-Control-Request-Method
     => 如果復雜請求設置了請求頭,則服務端需要設置允許某請求頭,否則“預檢”不通過
        Access-Control-Request-Headers

   看圖:

   技術分享圖片

  如果是非簡單請求的話,我們在視圖函數中應該這樣寫

from django.shortcuts import render
from django.http import JsonResponse
# Create your views here.
def books(request):

    obj = JsonResponse([西遊記,三國演義,水滸傳],safe=False)
    # obj["Access-Control-Allow-Origin"] = "*"
    obj["Access-Control-Allow-Origin"] = "http://127.0.0.1:8000"
    
    #處理預檢的options請求,這個預檢的響應,我們需要在響應頭裏面加上下面的內容
    if request.method == OPTIONS:
       
        obj[Access-Control-Allow-Headers] = "content-type"  # 也可以在裏面寫自定義的請求頭,當然也可以寫"*"
        obj[Access-Control-Allow-Methods] = "DELETE,PUT"  # 通過預檢的請求方法設置,同樣可以寫"*"

    return obj

三 . django中自帶的contentType表

  models.py文件

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation

class Electrics(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    coupons = GenericRelation(to=Coupon)  # 用於反向查詢,不會生成表字段
    def __str__(self):
        return self.name

class Foods(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    coupons = GenericRelation(to=Coupon)
    def __str__(self):
        return self.name

class Coupon(models.Model):
    name = models.CharField(max_length=32)

    content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()  # 存的是關聯的那張表對應的id
    content_object = GenericForeignKey(content_type, object_id)  # 對象.content_object直接能找到優惠券關聯的商品對象
    def __str__(self):
        return self.name

  技術分享圖片

  技術分享圖片

  視圖函數

from app01 import models
from django.shortcuts import render, HttpResponse
from django.contrib.contenttypes.models import ContentType

def test(request):
    if request.method == GET:
        # ContentType表對象有model_class() 方法,取到對應model
        content = ContentType.objects.filter(app_label=app01, model=electrics).first()  # 表名小寫
        elec_class = content.model_class()  # elec_class 就相當於models.Electrics
        res = elec_class.objects.all()
        print(res)  # <QuerySet [<Electrics: 電視>, <Electrics: 冰箱>]>
        return HttpResponse(ok)

        # 為電視(id=1)創建一條優惠記錄
        tv = models.Electrics.objects.filter(id=1).first()
        models.Coupon.objects.create(name=電視優惠券, content_object=tv)
        return HttpResponse(ok)

        # 查詢優惠券(id=1)綁定了哪個商品
        coupon_obj = models.Coupon.objects.filter(id=1).first()
        prod = coupon_obj.content_object
        print(prod.name)  # 電視
        print(prod.price)  # 1000
        return HttpResponse(ok)

        # 查詢電視(id=1)的所有優惠券
        tv = models.Electrics.objects.filter(id=1).first()
        res = tv.coupons.all()
        print(res)  # <QuerySet [<Coupon: 電視優惠券>]>
        return HttpResponse(ok)

  !!! 註意:ContentType只運用於1對多的關系!!!並且多的那張表中有多個ForeignKey字段。

跨域,CORS和contentType表