* 当body 为 FileBufferingReadStream,可能会出现request.Body.Length=0的情况

* 修改package id 避免下载到原版
* 发布到nuget.org
This commit is contained in:
nsnail 2022-09-08 17:56:38 +08:00
parent 36ad6e1e78
commit c2eb375f91
3 changed files with 186 additions and 160 deletions

24
nuget/build-and-push.ps1 Normal file
View File

@ -0,0 +1,24 @@
# ¶¨Òå²ÎÊý
Param(
# Nuget APIKey
[string] $apikey
)
if ($apikey -eq $null -or $apikey -eq "")
{
Write-Error "±ØÐëÖ¸¶¨apiKey";
return;
}
rm -r ../src/Ocelot/bin/Release
dotnet build -c Release ../Ocelot.sln
$files = Get-ChildItem -Path ../src/Ocelot/bin/Release -Filter *-ns*.nupkg
foreach($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
}
$files = Get-ChildItem -Path ../src/Ocelot/bin/Release -Filter *-ns*.snupkg
foreach($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
}

View File

@ -1,41 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<NoPackageAnalysis>true</NoPackageAnalysis> <NoPackageAnalysis>true</NoPackageAnalysis>
<Description>Ocelot is an API Gateway. The project is aimed at people using .NET running a micro services / service orientated architecture that need a unified point of entry into their system. In particular I want easy integration with IdentityServer reference and bearer tokens. reference tokens. Ocelot is a bunch of middlewares in a specific order. Ocelot manipulates the HttpRequest object into a state specified by its configuration until it reaches a request builder middleware where it creates a HttpRequestMessage object which is used to make a request to a downstream service. The middleware that makes the request is the last thing in the Ocelot pipeline. It does not call the next middleware. The response from the downstream service is stored in a per request scoped repository and retrived as the requests goes back up the Ocelot pipeline. There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. That is basically it with a bunch of other features.</Description> <Description>Ocelot is an API Gateway. The project is aimed at people using .NET running a micro services / service orientated architecture that need a unified point of entry into their system. In particular I want easy integration with IdentityServer reference and bearer tokens. reference tokens. Ocelot is a bunch of middlewares in a specific order. Ocelot manipulates the HttpRequest object into a state specified by its configuration until it reaches a request builder middleware where it creates a HttpRequestMessage object which is used to make a request to a downstream service. The middleware that makes the request is the last thing in the Ocelot pipeline. It does not call the next middleware. The response from the downstream service is stored in a per request scoped repository and retrived as the requests goes back up the Ocelot pipeline. There is a piece of middleware that maps the HttpResponseMessage onto the HttpResponse object and that is returned to the client. That is basically it with a bunch of other features.</Description>
<AssemblyTitle>Ocelot</AssemblyTitle> <AssemblyTitle>Ocelot</AssemblyTitle>
<VersionPrefix>0.0.0-dev</VersionPrefix> <VersionPrefix>18.0.1-ns1</VersionPrefix>
<AssemblyName>Ocelot</AssemblyName> <AssemblyName>Ocelot</AssemblyName>
<PackageId>Ocelot</PackageId> <PackageId>Ocelot.NS</PackageId>
<PackageTags>API Gateway;.NET core</PackageTags> <PackageTags>API Gateway;.NET core</PackageTags>
<PackageProjectUrl>https://github.com/ThreeMammals/Ocelot</PackageProjectUrl> <PackageProjectUrl>https://github.com/ThreeMammals/Ocelot</PackageProjectUrl>
<PackageIconUrl>http://github.com/images/ocelot_logo.png</PackageIconUrl> <PackageIconUrl>http://github.com/images/ocelot_logo.png</PackageIconUrl>
<RuntimeIdentifiers>win10-x64;osx.10.11-x64;osx.10.12-x64;win7-x64</RuntimeIdentifiers> <RuntimeIdentifiers>win10-x64;osx.10.11-x64;osx.10.12-x64;win7-x64</RuntimeIdentifiers>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<Authors>Tom Pallister</Authors> <Authors>Tom Pallister</Authors>
<CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>..\..\codeanalysis.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType> <DebugType>full</DebugType>
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="10.3.6" /> <PackageReference Include="FluentValidation" Version="10.3.6" />
<PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="6.0.1" /> <PackageReference Include="Microsoft.AspNetCore.MiddlewareAnalysis" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="3.1.22"> <PackageReference Include="Microsoft.Extensions.DiagnosticAdapter" Version="3.1.22">
<NoWarn>NU1701</NoWarn> <NoWarn>NU1701</NoWarn>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.1" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164"> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.164">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" /> <PackageReference Update="Microsoft.SourceLink.GitHub" Version="1.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,119 +1,121 @@
namespace Ocelot.Request.Mapper namespace Ocelot.Request.Mapper
{ {
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Ocelot.Configuration; using Ocelot.Configuration;
using Ocelot.Responses; using Ocelot.Responses;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
public class RequestMapper : IRequestMapper public class RequestMapper : IRequestMapper
{ {
private readonly string[] _unsupportedHeaders = { "host" }; private readonly string[] _unsupportedHeaders = { "host" };
public async Task<Response<HttpRequestMessage>> Map(HttpRequest request, DownstreamRoute downstreamRoute) public async Task<Response<HttpRequestMessage>> Map(HttpRequest request, DownstreamRoute downstreamRoute)
{ {
try try
{ {
var requestMessage = new HttpRequestMessage() var requestMessage = new HttpRequestMessage()
{ {
Content = await MapContent(request), Content = await MapContent(request),
Method = MapMethod(request, downstreamRoute), Method = MapMethod(request, downstreamRoute),
RequestUri = MapUri(request), RequestUri = MapUri(request),
Version = downstreamRoute.DownstreamHttpVersion, Version = downstreamRoute.DownstreamHttpVersion,
}; };
MapHeaders(request, requestMessage); MapHeaders(request, requestMessage);
return new OkResponse<HttpRequestMessage>(requestMessage); return new OkResponse<HttpRequestMessage>(requestMessage);
} }
catch (Exception ex) catch (Exception ex)
{ {
return new ErrorResponse<HttpRequestMessage>(new UnmappableRequestError(ex)); return new ErrorResponse<HttpRequestMessage>(new UnmappableRequestError(ex));
} }
} }
private async Task<HttpContent> MapContent(HttpRequest request) private async Task<HttpContent> MapContent(HttpRequest request)
{ {
if (request.Body == null || (request.Body.CanSeek && request.Body.Length <= 0)) // if (request.Body == null || (request.Body.CanSeek && request.Body.Length)
{ // ↑ 当body 为 FileBufferingReadStream可能会出现request.Body.Length=0的情况 那么 就会漏掉后续的流程 。修改为 ↓
return null; if (request.Body.CanSeek && request.Body.Length <= 0 && (request.ContentLength ?? 0) <=0)
} {
return null;
// Never change this to StreamContent again, I forgot it doesnt work in #464. }
var content = new ByteArrayContent(await ToByteArray(request.Body));
// Never change this to StreamContent again, I forgot it doesnt work in #464.
if (!string.IsNullOrEmpty(request.ContentType)) var content = new ByteArrayContent(await ToByteArray(request.Body));
{
content.Headers if (!string.IsNullOrEmpty(request.ContentType))
.TryAddWithoutValidation("Content-Type", new[] { request.ContentType }); {
} content.Headers
.TryAddWithoutValidation("Content-Type", new[] { request.ContentType });
AddHeaderIfExistsOnRequest("Content-Language", content, request); }
AddHeaderIfExistsOnRequest("Content-Location", content, request);
AddHeaderIfExistsOnRequest("Content-Range", content, request); AddHeaderIfExistsOnRequest("Content-Language", content, request);
AddHeaderIfExistsOnRequest("Content-MD5", content, request); AddHeaderIfExistsOnRequest("Content-Location", content, request);
AddHeaderIfExistsOnRequest("Content-Disposition", content, request); AddHeaderIfExistsOnRequest("Content-Range", content, request);
AddHeaderIfExistsOnRequest("Content-Encoding", content, request); AddHeaderIfExistsOnRequest("Content-MD5", content, request);
AddHeaderIfExistsOnRequest("Content-Disposition", content, request);
return content; AddHeaderIfExistsOnRequest("Content-Encoding", content, request);
}
return content;
private void AddHeaderIfExistsOnRequest(string key, HttpContent content, HttpRequest request) }
{
if (request.Headers.ContainsKey(key)) private void AddHeaderIfExistsOnRequest(string key, HttpContent content, HttpRequest request)
{ {
content.Headers if (request.Headers.ContainsKey(key))
.TryAddWithoutValidation(key, request.Headers[key].ToList()); {
} content.Headers
} .TryAddWithoutValidation(key, request.Headers[key].ToList());
}
private HttpMethod MapMethod(HttpRequest request, DownstreamRoute downstreamRoute) }
{
if (!string.IsNullOrEmpty(downstreamRoute?.DownstreamHttpMethod)) private HttpMethod MapMethod(HttpRequest request, DownstreamRoute downstreamRoute)
{ {
return new HttpMethod(downstreamRoute.DownstreamHttpMethod); if (!string.IsNullOrEmpty(downstreamRoute?.DownstreamHttpMethod))
} {
return new HttpMethod(downstreamRoute.DownstreamHttpMethod);
return new HttpMethod(request.Method); }
}
return new HttpMethod(request.Method);
private Uri MapUri(HttpRequest request) }
{
return new Uri(request.GetEncodedUrl()); private Uri MapUri(HttpRequest request)
} {
return new Uri(request.GetEncodedUrl());
private void MapHeaders(HttpRequest request, HttpRequestMessage requestMessage) }
{
foreach (var header in request.Headers) private void MapHeaders(HttpRequest request, HttpRequestMessage requestMessage)
{ {
if (IsSupportedHeader(header)) foreach (var header in request.Headers)
{ {
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); if (IsSupportedHeader(header))
} {
} requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
} }
}
private bool IsSupportedHeader(KeyValuePair<string, StringValues> header) }
{
return !_unsupportedHeaders.Contains(header.Key.ToLower()); private bool IsSupportedHeader(KeyValuePair<string, StringValues> header)
} {
return !_unsupportedHeaders.Contains(header.Key.ToLower());
private async Task<byte[]> ToByteArray(Stream stream) }
{
using (stream) private async Task<byte[]> ToByteArray(Stream stream)
{ {
using (var memStream = new MemoryStream()) using (stream)
{ {
await stream.CopyToAsync(memStream); using (var memStream = new MemoryStream())
return memStream.ToArray(); {
} await stream.CopyToAsync(memStream);
} return memStream.ToArray();
} }
} }
} }
}
}