Angular 4 对 Django Rest 框架的 HTTP 请求

Posted

技术标签:

【中文标题】Angular 4 对 Django Rest 框架的 HTTP 请求【英文标题】:Angular 4 HTTP requests to Django Rest Framework 【发布时间】:2018-05-02 03:20:48 【问题描述】:

我在从 Angular 4 发送到我创建的 Django Rest Framework API 的 HTTP 请求中的(我认为)授权标头相关的问题的任何地方找到答案时遇到问题。让我们开始吧:

编辑: 确认问题与授权有关,因为我现在也在使用 django-cors-headers 来摆脱 4200 端口的 CORS 问题(因为它被认为是不同的来源)。剩下的问题只是我在向 API 发出请求时收到“未经授权”的消息。我开始认为这是一个编码问题,因为当我尝试使用 httpie 进行以下请求时会显示以下消息:

http GET http://localhost:8000/api/groups/ "Authorization: Basic admin:password"

然后显示消息:


    "detail": "Invalid basic header. Credentials not correctly base64 encoded."

在 settings.py 中,我确保权限类和身份验证类都可用。

REST_FRAMEWORK = 
'DEFAULT_AUTHENTICATION_CLASSES': [
    'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.IsAdminUser'
],

...

CORS_ORIGIN_WHITELIST = [
    'localhost:4200',
]

在views.py中,这可能是我的错,因为我在尝试从Angular发送请求时遇到控制台错误-> Rest API是'No'Access-Control-Allow-Origin'标头存在请求的资源。这是不真实的,因为当我删除身份验证需求时它不会抱怨这一点。

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer
    permission_classes = (IsAdminUser, )
    authentication_classes = (BasicAuthentication, )

    def list(self, request):
        queryset = User.objects.all().order_by('-date_joined')
        serializer = UserSerializer(queryset, many=True, context='request': request)
        return Response(serializer.data,
                        status=200)

Angular 开发服务器在 localhost:4200 上运行,而 django 保留在其默认的 localhost:8000 上。

我将包含 urls.py 以作好衡量:

from django.conf.urls import url, include
from rest_framework import routers
from backend.api import views
from django.contrib import admin

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'info', views.InfoViewSet)

urlpatterns = [
    url(r'^api/', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'^admin/', admin.site.urls),
]

请注意,我可以使用 httpie 使用授权标头发出请求并获得响应,如下所示:

http GET http://localhost:8000/api/users/ -a admin:password

最后,这是发出请求的 Angular 代码(我包含了所有内容,以便也可以检查导入):

import  Component, OnInit  from '@angular/core';
import  HttpClient, HttpHeaders  from '@angular/common/http';

@Component(
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
)
export class AppComponent implements OnInit 
  title = 'app';
  results: string[];

  constructor(private http: HttpClient) 

  ngOnInit(): void 

    this.http.get(
      'http://localhost:8000/api/users/',
       headers: new HttpHeaders().set('Authorization', 'Basic admin:password'), 
      ).subscribe(
        data => 
          this.results = data;
      ,
        err => 
          console.log("ERROR RETREIVING USERS");
      );
  

我还导入了 HttpClientModule 并将其列在我的 app.module 中的“导入”下。

【问题讨论】:

嗨..试试他的.http.get(url) 【参考方案1】:

不同的端口被认为是不同的来源,因此您当然会在 localhost 上收到跨域错误 (CORS)。这是与您的服务器一起的浏览器安全功能。

安装 django-cross-header 包解决跨域错误。

【讨论】:

这似乎不是 CORS 问题,我查看了 django-cors-headers。如果有的话,授权存在问题,但我还无法弄清楚这是否是我添加标头的方式,如果它是身份验证的 django 端选择还是其他什么......我添加了 django-cors-headers 来衡量但是什么都没有改变。 See this。我遇到过类似的问题,其中一个建议的原因是使用身份验证会通过设计强制执行更严格的策略。我用了这个,它得到了解决。不同之处在于我们使用的是 Angular 2 和 django,但这个问题通常与浏览器而不是前端框架相关。 感谢您的帮助,我认为使用 django-cors-headers 解决了部分问题,我只是不知道这里有两个问题!我终于通过使用您的解决方案并使用用户名:密码部分的“btoa”函数对授权标头进行编码来使其工作。 不客气。如果有帮助,您可以将答案标记为已接受,它可以帮助其他人解决同样的问题(我也是:D)。如果可能,还请描述或发布链接到您的角度部分的编码解决方案。 我也添加了自己的解决方案,并解释了它发生的原因。很难找到信息,打印输出也没什么帮助。但多亏了你和 httpie,它终于可以工作了:D【参考方案2】:

我使用相同的后端框架,我找到的解决方案是使用正确的主机构建我的项目

ng build --production -host=myDomain.com // try localhost -p 8080 in your case

并替换

Access-Control-Allow-Origin: 'http://localhost:4200'

Access-Control-Allow-Origin: '*'

【讨论】:

【参考方案3】:

问题通过两种方式解决。首先,我没有正确确保从 Angular 4 发送请求的源点启用 CORS。 @kmcodes 使用 django-cors-headers 的解决方案是一个很好的解决方案,在将它添加到我的项目后,我不再遇到“Access-Control-Allow-Origin”丢失的问题。

问题的第二部分是在我为 Angular 4 发送的请求添加的标头中。以下是我需要进行的更改:

this.http.get(
      'http://localhost:8000/api/users/',
       headers: new HttpHeaders().set('Authorization', 'Basic admin:password'), 
      ).subscribe(
        data => 
          this.results = data;
      ,
        err => 
          console.log("ERROR RETREIVING USERS");
      );

到这里:

this.http.get(
      'http://localhost:8000/api/users/',
       headers: new HttpHeaders().set('Authorization', 'Basic ' + btoa('admin:password')), 
      ).subscribe(
        data => 
          this.results = data;
      ,
        err => 
          console.log("ERROR RETREIVING USERS");
      );

我在使用 httpie 检查我的请求时得到了提示,并看到当我没有使用 -a 标志添加身份验证参数而是使用“授权”标头时。这给了我一个错误,指出请求失败,错误代码 401,未经授权,因为用户名:密码部分未使用 base64 编码。在 Angular 4(可能之前)中, btoa() 解决了这个问题。

【讨论】:

在对基于 HTTP 请求的问题进行故障排除时,我也会使用 requestbin。

以上是关于Angular 4 对 Django Rest 框架的 HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章

Django、REST 和 Angular 路由

django-rest-auth + django-allauth + angular2

Angular 2 前端 django 2 REST 框架后端用户身份验证

使用 angular 向 django-rest 发送 DELETE 请求被解释为 OPTIONS

Django REST框架+ Angular项目上的令牌认证

Angular 2登录到Django Rest Framework后端